/* packet-epl.c * Routines for "Ethernet Powerlink 2.0" dissection * (ETHERNET Powerlink V2.0 Communication Profile Specification Draft Standard Version 1.0.0) * * Copyright (c) 2006: Zurich University of Applied Sciences Winterthur (ZHW) * Institute of Embedded Systems (InES) * http://ines.zhwin.ch * * - Dominic Bchaz * - Damir Bursic * - David Bchi * * * $Id$ * * A plugin for: * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1999 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "packet-epl.h" /* Initialize the protocol and registered fields */ static gint proto_epl = -1; static gint hf_epl_mtyp = -1; static gint hf_epl_dest = -1; static gint hf_epl_src = -1; static gint hf_epl_soc_mc = -1; static gint hf_epl_soc_ps = -1; static gint hf_epl_soc_nettime = -1; static gint hf_epl_soc_relativetime = -1; static gint hf_epl_preq_ms = -1; static gint hf_epl_preq_ea = -1; static gint hf_epl_preq_rd = -1; static gint hf_epl_preq_pdov = -1; static gint hf_epl_preq_size = -1; static gint hf_epl_preq_pl = -1; static gint hf_epl_pres_stat_ms = -1; static gint hf_epl_pres_stat_cs = -1; static gint hf_epl_pres_ms = -1; static gint hf_epl_pres_en = -1; static gint hf_epl_pres_rd = -1; static gint hf_epl_pres_pr = -1; static gint hf_epl_pres_rs = -1; static gint hf_epl_pres_pdov = -1; static gint hf_epl_pres_size = -1; static gint hf_epl_pres_pl = -1; static gint hf_epl_soa_stat_ms = -1; static gint hf_epl_soa_stat_cs = -1; static gint hf_epl_soa_ea = -1; static gint hf_epl_soa_er = -1; static gint hf_epl_soa_svid = -1; static gint hf_epl_soa_svtg = -1; static gint hf_epl_soa_eplv = -1; static gint hf_epl_asnd_svid = -1; static gint hf_epl_asnd_data = -1; /*IdentResponse*/ static gint hf_epl_asnd_identresponse_en = -1; static gint hf_epl_asnd_identresponse_ec = -1; static gint hf_epl_asnd_identresponse_pr = -1; static gint hf_epl_asnd_identresponse_rs = -1; static gint hf_epl_asnd_identresponse_stat_ms = -1; static gint hf_epl_asnd_identresponse_stat_cs = -1; static gint hf_epl_asnd_identresponse_ever = -1; static gint hf_epl_asnd_identresponse_feat = -1; static gint hf_epl_asnd_identresponse_mtu = -1; static gint hf_epl_asnd_identresponse_pis = -1; static gint hf_epl_asnd_identresponse_pos = -1; static gint hf_epl_asnd_identresponse_rst = -1; static gint hf_epl_asnd_identresponse_dt = -1; static gint hf_epl_asnd_identresponse_vid = -1; static gint hf_epl_asnd_identresponse_productcode = -1; static gint hf_epl_asnd_identresponse_rno = -1; static gint hf_epl_asnd_identresponse_sno = -1; static gint hf_epl_asnd_identresponse_vex1 = -1; static gint hf_epl_asnd_identresponse_vcd = -1; static gint hf_epl_asnd_identresponse_vct = -1; static gint hf_epl_asnd_identresponse_ad = -1; static gint hf_epl_asnd_identresponse_at = -1; static gint hf_epl_asnd_identresponse_ipa = -1; static gint hf_epl_asnd_identresponse_snm = -1; static gint hf_epl_asnd_identresponse_gtw = -1; static gint hf_epl_asnd_identresponse_hn = -1; static gint hf_epl_asnd_identresponse_vex2 = -1; /*StatusResponse*/ static gint hf_epl_asnd_statusresponse_en = -1; static gint hf_epl_asnd_statusresponse_ec = -1; static gint hf_epl_asnd_statusresponse_pr = -1; static gint hf_epl_asnd_statusresponse_rs = -1; static gint hf_epl_asnd_statusresponse_stat_ms = -1; static gint hf_epl_asnd_statusresponse_stat_cs = -1; static gint hf_epl_asnd_statusresponse_seb = -1; /*StaticErrorBitField */ static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit0 = -1; static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit1 = -1; static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit2 = -1; static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit3 = -1; static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit4 = -1; static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit5 = -1; static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit7 = -1; static gint hf_epl_asnd_statusresponse_seb_devicespecific_err = -1; /*List of Errors/Events*/ static gint hf_epl_asnd_statusresponse_el = -1; static gint hf_epl_asnd_statusresponse_el_entry = -1; static gint hf_epl_asnd_statusresponse_el_entry_type = -1; static gint hf_epl_asnd_statusresponse_el_entry_type_profile = -1; static gint hf_epl_asnd_statusresponse_el_entry_type_mode = -1; static gint hf_epl_asnd_statusresponse_el_entry_type_bit14 = -1; static gint hf_epl_asnd_statusresponse_el_entry_type_bit15 = -1; static gint hf_epl_asnd_statusresponse_el_entry_code = -1; static gint hf_epl_asnd_statusresponse_el_entry_time = -1; static gint hf_epl_asnd_statusresponse_el_entry_add = -1; /*NMTRequest*/ static gint hf_epl_asnd_nmtrequest_rcid = -1; static gint hf_epl_asnd_nmtrequest_rct = -1; static gint hf_epl_asnd_nmtrequest_rcd = -1; /*NMTCommand*/ static gint hf_epl_asnd_nmtcommand_cid = -1; static gint hf_epl_asnd_nmtcommand_cdat = -1; static gint hf_epl_asnd_nmtcommand_nmtnetparameterset_mtu = -1; static gint hf_epl_asnd_nmtcommand_nmtnethostnameset_hn = -1; static gint hf_epl_asnd_nmtcommand_nmtflusharpentry_nid = -1; static gint hf_epl_asnd_nmtcommand_nmtpublishtime_dt = -1; /*Asynchronuous SDO Sequence Layer*/ static gint hf_epl_asnd_sdo_seq_receive_sequence_number = -1; static gint hf_epl_asnd_sdo_seq_receive_con = -1; static gint hf_epl_asnd_sdo_seq_send_sequence_number = -1; static gint hf_epl_asnd_sdo_seq_send_con = -1; /*Asynchronuous SDO Command Layer*/ static gint hf_epl_asnd_sdo_cmd_transaction_id = -1; static gint hf_epl_asnd_sdo_cmd_response = -1; static gint hf_epl_asnd_sdo_cmd_abort = -1; static gint hf_epl_asnd_sdo_cmd_segmentation = -1; static gint hf_epl_asnd_sdo_cmd_command_id = -1; static gint hf_epl_asnd_sdo_cmd_segment_size = -1; static gint hf_epl_asnd_sdo_cmd_data_size = -1; static gint hf_epl_asnd_sdo_cmd_abort_code = -1; static gint hf_epl_asnd_sdo_cmd_abort_flag = -1; static gint hf_epl_asnd_sdo_cmd_segmentation_flag = -1; static gint hf_epl_asnd_sdo_cmd_cmd_valid_test = -1; static gint hf_epl_asnd_sdo_actual_command_id = -1; static gint hf_epl_asnd_sdo_cmd_write_by_index_index = -1; static gint hf_epl_asnd_sdo_cmd_write_by_index_subindex = -1; static gint hf_epl_asnd_sdo_cmd_write_by_index_data = -1; static gint hf_epl_asnd_sdo_cmd_write_by_index_response = -1; static gint hf_epl_asnd_sdo_cmd_read_by_index_index = -1; static gint hf_epl_asnd_sdo_cmd_read_by_index_subindex = -1; static gint hf_epl_asnd_sdo_cmd_read_by_index_data = -1; static gint hf_epl_asnd_sdo_cmd_read_by_index_response = -1; static gint hf_epl_asnd_sdo_actual_segment_size = -1; static gint hf_epl_asnd_sdo_actual_payload_size_read = -1; /* Initialize the subtree pointers */ static gint ett_epl = -1; static gint ett_epl_seb = -1; static gint ett_epl_el = -1; static gint ett_epl_el_entry = -1; static gint ett_epl_el_entry_type = -1; static gint ett_epl_sdo_entry_type = -1; /* Define the tap for epl */ /*static gint epl_tap = -1;*/ /* Code to actually dissect the packets */ static gboolean dissect_epl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint8 epl_mtyp, epl_src, epl_dest, epl_soa_svid, epl_asnd_svid; const gchar *src_str, *dest_str, *src_str_abbr, *dest_str_abbr; gchar *info_str; /* static epl_info_t mi; */ /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *epl_tree, *epl_src_item, *epl_dest_item; gint offset = 0; info_str = ep_alloc(200); info_str[0] = 0; if (tvb_length_remaining(tvb, offset) < 3) { /* Not enough data for an EPL header; don't try to interpret it */ return FALSE; } /* Make entries in Protocol column and Info column on summary display */ if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "EPL"); } /* Get message type */ epl_mtyp = tvb_get_guint8(tvb, EPL_MTYP_OFFSET) & 0x7F; /* tap */ /* mi.epl_mtyp = epl_mtyp; tap_queue_packet(epl_tap, pinfo, &mi); */ /* Get Destination */ epl_dest = tvb_get_guint8(tvb, EPL_DEST_OFFSET); dest_str = decode_epl_address(epl_dest); dest_str_abbr = decode_epl_address_abbrev(epl_dest); /* Get Source */ epl_src = tvb_get_guint8(tvb, EPL_SRC_OFFSET); src_str = decode_epl_address(epl_src); src_str_abbr = decode_epl_address_abbrev(epl_src); /* Choose the right string for "Info" column (message type) */ switch (epl_mtyp) { case EPL_SOC: g_snprintf(info_str, 200, "SoC dest = %3d%s src = %3d%s ", epl_dest, dest_str_abbr, epl_src, src_str_abbr); break; case EPL_PREQ: g_snprintf(info_str, 200, "PReq dest = %3d%s src = %3d%s ", epl_dest, dest_str_abbr, epl_src, src_str_abbr); break; case EPL_PRES: g_snprintf(info_str, 200, "PRes dest = %3d%s src = %3d%s ", epl_dest, dest_str_abbr, epl_src, src_str_abbr); break; case EPL_SOA: epl_soa_svid = tvb_get_guint8(tvb, EPL_SOA_SVID_OFFSET); /* Get RequestedServiceID */ g_snprintf(info_str, 200, "SoA dest = %3d%s src = %3d%s %s ", epl_dest, dest_str_abbr, epl_src, src_str_abbr, match_strval(epl_soa_svid, soa_svid_vals)); break; case EPL_ASND: epl_asnd_svid = tvb_get_guint8(tvb, EPL_ASND_SVID_OFFSET); /* Get ServiceID */ g_snprintf(info_str, 200, "ASnd dest = %3d%s src = %3d%s %s ", epl_dest, dest_str_abbr, epl_src, src_str_abbr, match_strval(epl_asnd_svid, asnd_svid_vals)); break; default: /* no valid EPL packet */ return FALSE; } if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); } if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, info_str); } if (tree) { /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_epl, tvb, 0, -1, TRUE); epl_tree = proto_item_add_subtree(ti, ett_epl); proto_tree_add_item(epl_tree, hf_epl_mtyp, tvb, offset, 1, TRUE); offset += 1; epl_dest_item = proto_tree_add_item(epl_tree, hf_epl_dest, tvb, offset, 1, TRUE); proto_item_append_text (epl_dest_item, dest_str); offset += 1; epl_src_item = proto_tree_add_item(epl_tree, hf_epl_src, tvb, offset, 1, TRUE); proto_item_append_text (epl_src_item, src_str); offset += 1; /* The rest of the epl-dissector depends on the message type */ switch (epl_mtyp) { case EPL_SOC: offset = dissect_epl_soc(epl_tree, tvb, offset); break; case EPL_PREQ: offset = dissect_epl_preq(epl_tree, tvb, offset); break; case EPL_PRES: offset = dissect_epl_pres(epl_tree, tvb, epl_src, offset); break; case EPL_SOA: offset = dissect_epl_soa(epl_tree, tvb, epl_src, offset); break; case EPL_ASND: offset = dissect_epl_asnd(tree, epl_tree, tvb, epl_src, offset); break; default: /* no valid EPL packet */ return FALSE; } } return TRUE; } const gchar* decode_epl_address (guchar adr) { const gchar *addr_str; addr_str = match_strval(adr, addr_str_vals); if (addr_str != NULL) { return addr_str; } else { if (( adr < EPL_MN_NODEID) && (adr > EPL_INVALID_NODEID)) { return addr_str_cn; } else { return addr_str_res; } } } /* Get the abbreviation for an EPL NodeID */ const gchar* decode_epl_address_abbrev (guchar adr) { const gchar *addr_str; addr_str = match_strval(adr, addr_str_abbr_vals); if (addr_str != NULL) { return addr_str; } else { if (( adr < EPL_MN_NODEID) && (adr > EPL_INVALID_NODEID)) { return addr_str_abbr_cn; } else { return addr_str_abbr_res; } } } gint dissect_epl_soc(proto_tree *epl_tree, tvbuff_t *tvb, gint offset) { nstime_t nettime; offset += 1; proto_tree_add_item(epl_tree, hf_epl_soc_mc, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_soc_ps, tvb, offset, 1, TRUE); offset += 2; nettime.secs = tvb_get_letohl(tvb, offset); nettime.nsecs = tvb_get_letohl(tvb, offset+4); proto_tree_add_time_format_value(epl_tree, hf_epl_soc_nettime, tvb, offset, 8, &nettime, "%s", abs_time_to_str(&nettime)); offset += 8; proto_tree_add_item(epl_tree, hf_epl_soc_relativetime, tvb, offset, 8, TRUE); offset += 8; return offset; } gint dissect_epl_preq(proto_tree *epl_tree, tvbuff_t *tvb, gint offset) { guint16 len; guint8 pdoversion; offset += 1; proto_tree_add_item(epl_tree, hf_epl_preq_ms, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_preq_ea, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_preq_rd, tvb, offset, 1, TRUE); offset += 2; pdoversion = tvb_get_guint8(tvb, offset); proto_tree_add_string_format(epl_tree, hf_epl_preq_pdov, tvb, offset, 1, "", "PDOVersion %d.%d", hi_nibble(pdoversion), lo_nibble(pdoversion)); offset += 2; proto_tree_add_item(epl_tree, hf_epl_preq_size, tvb, offset, 2, TRUE); /* get size of payload */ len = tvb_get_letohs(tvb, offset); offset += 2; if (len > 0) { proto_tree_add_item(epl_tree, hf_epl_preq_pl, tvb, offset, len, TRUE); } offset += len; return offset; } gint dissect_epl_pres(proto_tree *epl_tree, tvbuff_t *tvb, guint8 epl_src, gint offset) { guint16 len; guint8 pdoversion; if (epl_src != EPL_MN_NODEID) /* check if the sender is CN or MN */ { proto_tree_add_item(epl_tree, hf_epl_pres_stat_cs, tvb, offset, 1, TRUE); } else /* MN */ { proto_tree_add_item(epl_tree, hf_epl_pres_stat_ms, tvb, offset, 1, TRUE); } offset += 1; proto_tree_add_item(epl_tree, hf_epl_pres_ms, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_pres_en, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_pres_rd, tvb, offset, 1, TRUE); offset += 1; proto_tree_add_item(epl_tree, hf_epl_pres_pr, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_pres_rs, tvb, offset, 1, TRUE); offset += 1; pdoversion = tvb_get_guint8(tvb, offset); proto_tree_add_string_format(epl_tree, hf_epl_pres_pdov, tvb, offset, 1, "", "PDOVersion %d.%d", hi_nibble(pdoversion), lo_nibble(pdoversion)); offset += 2; proto_tree_add_item(epl_tree, hf_epl_pres_size, tvb, offset, 2, TRUE); /* get size of payload */ len = tvb_get_letohs(tvb, offset); offset += 2; if (len > 0) { proto_tree_add_item(epl_tree, hf_epl_pres_pl, tvb, offset, len, TRUE); } offset += len; return offset; } gint dissect_epl_soa(proto_tree *epl_tree, tvbuff_t *tvb, guint8 epl_src, gint offset) { guint8 eplversion; if (epl_src != EPL_MN_NODEID) /* check if CN or MN */ { proto_tree_add_item(epl_tree, hf_epl_soa_stat_cs, tvb, offset, 1, TRUE); } else /* MN */ { proto_tree_add_item(epl_tree, hf_epl_soa_stat_ms, tvb, offset, 1, TRUE); } offset += 1; proto_tree_add_item(epl_tree, hf_epl_soa_ea, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_soa_er, tvb, offset, 1, TRUE); offset += 2; proto_tree_add_item(epl_tree, hf_epl_soa_svid, tvb, offset, 1, TRUE); offset += 1; proto_tree_add_item(epl_tree, hf_epl_soa_svtg, tvb, offset, 1, TRUE); offset += 1; eplversion = tvb_get_guint8(tvb, offset); proto_tree_add_string_format(epl_tree, hf_epl_soa_eplv, tvb, offset, 1, "", "EPLVersion %d.%d", hi_nibble(eplversion), lo_nibble(eplversion)); offset += 1; return offset; } gint dissect_epl_asnd(proto_tree *tree, proto_tree *epl_tree, tvbuff_t *tvb, guint8 epl_src, gint offset) { guint16 svid; proto_tree_add_item(epl_tree, hf_epl_asnd_svid, tvb, offset, 1, TRUE); /* get ServiceID of payload */ svid = tvb_get_guint8(tvb, offset); offset += 1; switch (svid) { case EPL_ASND_IDENTRESPONSE: offset = dissect_epl_asnd_ires(epl_tree, tvb, epl_src, offset); break; case EPL_ASND_STATUSRESPONSE: offset = dissect_epl_asnd_sres(tree, epl_tree, tvb, epl_src, offset); break; case EPL_ASND_NMTREQUEST: offset = dissect_epl_asnd_nmtreq(epl_tree, tvb, offset); break; case EPL_ASND_NMTCOMMAND: offset = dissect_epl_asnd_nmtcmd(epl_tree, tvb, offset); break; case EPL_ASND_SDO: offset = dissect_epl_asnd_sdo(epl_tree, tvb, offset); break; } return offset; } gint dissect_epl_asnd_nmtreq(proto_tree *epl_tree, tvbuff_t *tvb, gint offset) { proto_tree_add_item(epl_tree, hf_epl_asnd_nmtrequest_rcid, tvb, offset, 1, TRUE); offset += 1; proto_tree_add_item(epl_tree, hf_epl_asnd_nmtrequest_rct, tvb, offset, 1, TRUE); offset += 1; proto_tree_add_item(epl_tree, hf_epl_asnd_nmtrequest_rcd, tvb, offset, -1, TRUE); return offset; } gint dissect_epl_asnd_nmtcmd(proto_tree *epl_tree, tvbuff_t *tvb, gint offset) { guint8 epl_asnd_nmtcommand_cid; proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_cid, tvb, offset, 1, TRUE); epl_asnd_nmtcommand_cid = tvb_get_guint8(tvb, offset); offset += 2; switch (epl_asnd_nmtcommand_cid) { case EPL_ASND_NMTCOMMAND_NMTNETHOSTNAMESET: proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_nmtnethostnameset_hn, tvb, offset, 32, TRUE); offset += 32; break; case EPL_ASND_NMTCOMMAND_NMTFLUSHARPENTRY: proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_nmtflusharpentry_nid, tvb, offset, 1, TRUE); offset += 1; break; case EPL_ASND_NMTCOMMAND_NMTPUBLISHTIME: proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_nmtpublishtime_dt, tvb, offset, 6, TRUE); offset += 6; break; default: proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_cdat, tvb, offset, -1, TRUE); } return offset; } gint dissect_epl_asnd_ires(proto_tree *epl_tree, tvbuff_t *tvb, guint8 epl_src, gint offset) { guint8 eplversion; guint32 epl_asnd_identresponse_ipa, epl_asnd_identresponse_snm, epl_asnd_identresponse_gtw; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_en, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_ec, tvb, offset, 1, TRUE); offset += 1; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_pr, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_rs, tvb, offset, 1, TRUE); offset += 1; if (epl_src != EPL_MN_NODEID) /* check if CN or MN */ { proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_stat_cs, tvb, offset, 1, TRUE); } else /* MN */ { proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_stat_ms, tvb, offset, 1, TRUE); } offset += 2; eplversion = tvb_get_guint8(tvb, offset); proto_tree_add_string_format(epl_tree, hf_epl_asnd_identresponse_ever, tvb, offset, 1, "", "EPLVersion %d.%d", hi_nibble(eplversion), lo_nibble(eplversion)); offset += 2; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_feat, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_mtu, tvb, offset, 2, TRUE); offset += 2; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_pis, tvb, offset, 2, TRUE); offset += 2; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_pos, tvb, offset, 2, TRUE); offset += 2; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_rst, tvb, offset, 4, TRUE); offset += 6; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_dt, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vid, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_productcode, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_rno, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_sno, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vex1, tvb, offset, 8, TRUE); offset += 8; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vcd, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vct, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_ad, tvb, offset, 4, TRUE); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_at, tvb, offset, 4, TRUE); offset += 4; epl_asnd_identresponse_ipa = tvb_get_ntohl(tvb, offset); proto_tree_add_ipv4(epl_tree , hf_epl_asnd_identresponse_ipa, tvb, offset, 4, epl_asnd_identresponse_ipa); offset += 4; epl_asnd_identresponse_snm = tvb_get_ntohl(tvb, offset); proto_tree_add_ipv4(epl_tree , hf_epl_asnd_identresponse_snm, tvb, offset, 4, epl_asnd_identresponse_snm); offset += 4; epl_asnd_identresponse_gtw = tvb_get_ntohl(tvb, offset); proto_tree_add_ipv4(epl_tree , hf_epl_asnd_identresponse_gtw, tvb, offset, 4, epl_asnd_identresponse_gtw); offset += 4; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_hn, tvb, offset, 32, TRUE); offset += 32; proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vex2, tvb, offset, 48, TRUE); offset += 48; return offset; } gint dissect_epl_asnd_sres(proto_tree *tree, proto_tree *epl_tree, tvbuff_t *tvb, guint8 epl_src, gint offset) { proto_item *ti_seb, *ti_el, *ti_el_entry, *ti_el_entry_type; proto_tree *epl_seb_tree, *epl_el_tree, *epl_el_entry_tree, *epl_el_entry_type_tree; guint number_of_entries, cnt; /* used for dissection of ErrorCodeList */ proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_en, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_ec, tvb, offset, 1, TRUE); offset += 1; proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_pr, tvb, offset, 1, TRUE); proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_rs, tvb, offset, 1, TRUE); offset += 1; if (epl_src != EPL_MN_NODEID) /* check if CN or MN */ { proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_stat_cs, tvb, offset, 1, TRUE); } else /* MN */ { proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_stat_ms, tvb, offset, 1, TRUE); } offset += 4; /* Subtree for the static errorr bitfield */ if (tree) { ti_seb = proto_tree_add_text(epl_tree, tvb, offset, 8, "StaticErrorBitfield"); epl_seb_tree = proto_item_add_subtree(ti_seb, ett_epl_seb); proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit0, tvb, offset, 1, TRUE); proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit1, tvb, offset, 1, TRUE); proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit2, tvb, offset, 1, TRUE); proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit3, tvb, offset, 1, TRUE); proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit4, tvb, offset, 1, TRUE); proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit5, tvb, offset, 1, TRUE); proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit7, tvb, offset, 1, TRUE); offset += 2; proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_devicespecific_err, tvb,offset, 8, TRUE); offset += 8; } /* List of errors / events */ if (tree) { /* get the number of entries in the error code list*/ number_of_entries = (tvb_length(tvb)-offset)/20; ti_el = proto_tree_add_text(epl_tree, tvb, offset, -1, "ErrorCodeList: %d entries", number_of_entries); epl_el_tree = proto_item_add_subtree(ti_el, ett_epl_el); /*Dissect the whole Error List (display each entry)*/ for (cnt = 0; cntIdentResponse */ { &hf_epl_asnd_identresponse_en, { "EN (Exception New)", "epl.asnd.ires.en", FT_UINT8, BASE_DEC, NULL, 0x10, "", HFILL }}, { &hf_epl_asnd_identresponse_ec, { "EC (Exception Clear)", "epl.asnd.ires.ec", FT_UINT8, BASE_DEC, NULL, 0x08, "", HFILL }}, { &hf_epl_asnd_identresponse_pr, { "PR (Priority)", "epl.asnd.ires.pr", FT_UINT8, BASE_DEC, VALS(epl_pr_vals), 0x38, "", HFILL }}, { &hf_epl_asnd_identresponse_rs, { "RS (RequestToSend)", "epl.asnd.ires.rs", FT_UINT8, BASE_DEC, NULL, 0x07, "", HFILL }}, { &hf_epl_asnd_identresponse_stat_ms, { "NMTStatus", "epl.asnd.ires.state", FT_UINT8, BASE_DEC, VALS(epl_nmt_ms_vals),0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_stat_cs, { "NMTStatus", "epl.asnd.ires.state", FT_UINT8, BASE_DEC, VALS(epl_nmt_cs_vals),0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_ever, { "EPLVersion", "epl.asnd.ires.eplver", FT_STRING, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_feat, { "FeatureFlags", "epl.asnd.ires.features", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_mtu, { "MTU", "epl.asnd.ires.mtu", FT_UINT16, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_pis, { "PollInSize", "epl.asnd.ires.pollinsize", FT_UINT16, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_pos, { "PollOutSize", "epl.asnd.ires.polloutsizes", FT_UINT16, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_rst, { "ResponseTime", "epl.asnd.ires.resptime", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_dt, { "DeviceType", "epl.asnd.ires.devicetype", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_vid, { "VendorId", "epl.asnd.ires.vendorid", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_productcode,{ "ProductCode", "epl.asnd.ires.productcode", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_rno, { "RevisionNumber", "epl.asnd.ires.revisionno", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_sno, { "SerialNumber", "epl.asnd.ires.serialno", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_vex1, { "VendorSpecificExtension1", "epl.asnd.ires.vendorext1", FT_UINT64, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_vcd, { "VerifyConfigurationDate", "epl.asnd.ires.confdate", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_vct, { "VerifyConfigurationTime", "epl.asnd.ires.conftime", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_ad, { "applicationSwDate", "epl.asnd.ires.appswdate", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_at, { "applicationSwTime", "epl.asnd.ires.appswtime", FT_UINT32, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_ipa, { "IPAddress", "epl.asnd.ires.ip", FT_IPv4, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_snm, { "SubnetMask", "epl.asnd.ires.subnet", FT_IPv4, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_gtw, { "DefaultGateway", "epl.asnd.ires.gateway", FT_IPv4, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_hn, { "HostName", "epl.asnd.ires.hostname", FT_STRING, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_identresponse_vex2, { "VendorSpecificExtension2", "epl.asnd.ires.vendorext2", FT_BYTES, BASE_DEC, NULL, 0x00, "", HFILL }}, /* ASnd-->StatusResponse */ { &hf_epl_asnd_statusresponse_en, { "EN (Exception New)", "epl.asnd.sres.en", FT_UINT8, BASE_DEC, NULL, 0x10, "", HFILL }}, { &hf_epl_asnd_statusresponse_ec, { "EC (Exception Clear)", "epl.asnd.sres.ec", FT_UINT8, BASE_DEC, NULL, 0x08, "", HFILL }}, { &hf_epl_asnd_statusresponse_pr, { "PR (Priority)", "epl.asnd.sres.pr", FT_UINT8, BASE_DEC, VALS(epl_pr_vals), 0x38, "", HFILL }}, { &hf_epl_asnd_statusresponse_rs, { "RS (RequestToSend)", "epl.asnd.sres.rs", FT_UINT8, BASE_DEC, NULL, 0x07, "", HFILL }}, { &hf_epl_asnd_statusresponse_stat_ms, { "NMTStatus", "epl.asnd.sres.stat", FT_UINT8, BASE_DEC, VALS(epl_nmt_ms_vals), 0x00, "", HFILL }}, { &hf_epl_asnd_statusresponse_stat_cs, { "NMTStatus", "epl.asnd.sres.stat", FT_UINT8, BASE_DEC, VALS(epl_nmt_cs_vals), 0x00, "", HFILL }}, { &hf_epl_asnd_statusresponse_seb, { "StaticErrorBitField", "epl.asnd.sres.seb", FT_BYTES, BASE_HEX, NULL, 0x00, "", HFILL }}, /*StaticErrorBitField */ { &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit0, { "Generic error", "epl.asnd.res.seb.bit0", FT_UINT8, BASE_DEC, NULL, 0x01, "", HFILL }}, { &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit1, { "Current", "epl.asnd.res.seb.bit1", FT_UINT8, BASE_DEC, NULL, 0x02, "", HFILL }}, { &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit2, { "Voltage", "epl.asnd.res.seb.bit2", FT_UINT8, BASE_DEC, NULL, 0x04, "", HFILL }}, { &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit3, { "Temperature", "epl.asnd.res.seb.bit3", FT_UINT8, BASE_DEC, NULL, 0x08, "", HFILL }}, { &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit4, { "Communication error", "epl.asnd.res.seb.bit4", FT_UINT8, BASE_DEC, NULL, 0x10, "", HFILL }}, { &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit5, { "Device profile specific", "epl.asnd.res.seb.bit5", FT_UINT8, BASE_DEC, NULL, 0x20, "", HFILL }}, { &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit7, { "Manufacturer specific", "epl.asnd.res.seb.bit7", FT_UINT8, BASE_DEC, NULL, 0x80, "", HFILL }}, { &hf_epl_asnd_statusresponse_seb_devicespecific_err, { "Device profile specific", "epl.asnd.res.seb.devicespecific_err",FT_BYTES, BASE_DEC,NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_statusresponse_el, { "ErrorsCodeList", "epl.asnd.sres.el", FT_BYTES, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_statusresponse_el_entry, { "Entry", "epl.asnd.sres.el.entry", FT_BYTES, BASE_DEC, NULL, 0x00, "", HFILL }}, /*List of Errors/Events*/ { &hf_epl_asnd_statusresponse_el_entry_type, { "Entry Type", "epl.asnd.sres.el.entry.type", FT_UINT16, BASE_HEX, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_statusresponse_el_entry_type_profile, { "Profile", "epl.asnd.sres.el.entry.type.profile", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "", HFILL }}, { &hf_epl_asnd_statusresponse_el_entry_type_mode, { "Mode", "epl.asnd.sres.el.entry.type.mode", FT_UINT16, BASE_DEC, NULL, 0x3000, "", HFILL }}, { &hf_epl_asnd_statusresponse_el_entry_type_bit14, { "Bit14", "epl.asnd.sres.el.entry.type.bit14", FT_UINT16, BASE_DEC, NULL, 0x4000, "", HFILL }}, { &hf_epl_asnd_statusresponse_el_entry_type_bit15, { "Bit15", "epl.asnd.sres.el.entry.type.bit15", FT_UINT16, BASE_DEC, NULL, 0x8000, "", HFILL }}, { &hf_epl_asnd_statusresponse_el_entry_code, { "Error Code", "epl.asnd.sres.el.entry.code", FT_UINT16, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_statusresponse_el_entry_time, { "Time Stamp", "epl.asnd.sres.el.entry.time", FT_UINT64, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_statusresponse_el_entry_add, { "Additional Information", "epl.asnd.sres.el.entry.add", FT_UINT64, BASE_DEC, NULL, 0x00, "", HFILL }}, /* ASnd-->NMTRequest */ { &hf_epl_asnd_nmtrequest_rcid, { "NMTRequestedCommandID", "epl.asnd.nmtrequest.rcid", FT_UINT8, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_nmtrequest_rct, { "NMTRequestedCommandTarget", "epl.asnd.nmtrequest.rct", FT_UINT8, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_nmtrequest_rcd, { "NMTRequestedCommandData", "epl.asnd.nmtrequest.rcd", FT_BYTES, BASE_DEC, NULL, 0x00, "", HFILL }}, /* ASnd-->NMTCommand */ { &hf_epl_asnd_nmtcommand_cid, { "NMTCommandId", "epl.asnd.nmtcommand.cid", FT_UINT8, BASE_DEC, VALS(asnd_cid_vals), 0x00, "", HFILL }}, { &hf_epl_asnd_nmtcommand_cdat, { "NMTCommandData", "epl.asnd.nmtcommand.cdat", FT_BYTES, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_nmtcommand_nmtnethostnameset_hn, { "HostName", "epl.asnd.nmtcommand.nmtnethostnameset.hn", FT_BYTES, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_nmtcommand_nmtflusharpentry_nid, { "NodeID", "epl.asnd.nmtcommand.nmtflusharpentry.nid", FT_UINT8, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_nmtcommand_nmtpublishtime_dt, { "DateTime", "epl.asnd.nmtcommand.nmtpublishtime.dt", FT_BYTES, BASE_DEC, NULL, 0x00, "", HFILL }}, /* ASnd-->SDO */ { &hf_epl_asnd_sdo_seq_receive_sequence_number, { "ReceiveSequenceNumber", "epl.asnd.sdo.seq.receive.sequence.number", FT_UINT8, BASE_DEC, NULL, 0xfc, "", HFILL }}, { &hf_epl_asnd_sdo_seq_receive_con, { "ReceiveCon", "epl.asnd.sdo.seq.receive.con", FT_UINT8, BASE_DEC, VALS(epl_sdo_receive_con_vals), 0x03, "", HFILL }}, { &hf_epl_asnd_sdo_seq_send_sequence_number, { "SendSequenceNumber", "epl.asnd.sdo.seq.send.sequence.number", FT_UINT8, BASE_DEC, NULL, 0xfc, "", HFILL }}, { &hf_epl_asnd_sdo_seq_send_con, { "SendCon", "epl.asnd.sdo.seq.send.con", FT_UINT8, BASE_DEC, VALS(epl_sdo_send_con_vals), 0x03, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_transaction_id, { "SDO Transaction ID", "epl.asnd.sdo.cmd.transaction.id", FT_UINT8, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_response, { "SDO Response", "epl.asnd.sdo.cmd.response", FT_UINT8, BASE_DEC, VALS(epl_sdo_asnd_cmd_response), 0x80, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_abort, { "SDO Abort", "epl.asnd.sdo.cmd.abort", FT_UINT8, BASE_DEC, VALS(epl_sdo_asnd_cmd_abort), 0x40, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_segmentation, { "SDO Segmentation", "epl.asnd.sdo.cmd.segmentation", FT_UINT8, BASE_DEC, VALS(epl_sdo_asnd_cmd_segmentation), 0x30, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_command_id, { "SDO Command ID", "epl.asnd.sdo.cmd.command.id", FT_UINT8, BASE_DEC, VALS(epl_sdo_asnd_commands), 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_segment_size, { "SDO Segment size", "epl.asnd.sdo.cmd.segment.size", FT_UINT8, BASE_DEC, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_data_size, { "SDO Data size", "epl.asnd.sdo.cmd.data.size", FT_UINT8, BASE_DEC, NULL, 0x00, "", HFILL } }, { &hf_epl_asnd_sdo_cmd_abort_code, { "SDO Transfer Abort", "epl.asnd.sdo.cmd.abort.code", FT_UINT8, BASE_HEX, VALS(sdo_cmd_abort_code), 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_write_by_index_index, { "SDO Write by Index, Index", "epl.asnd.sdo.cmd.write.by.index.index", FT_UINT16, BASE_HEX, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_write_by_index_subindex, { "SDO Write by Index, SubIndex", "epl.asnd.sdo.cmd.write.by.index.subindex", FT_UINT8, BASE_HEX, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_read_by_index_index, { "SDO Read by Index, Index", "epl.asnd.sdo.cmd.read.by.index.index", FT_UINT16, BASE_HEX, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_read_by_index_subindex, { "SDO Read by Index, SubIndex", "epl.asnd.sdo.cmd.read.by.index.subindex", FT_UINT8, BASE_HEX, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_write_by_index_data, { "Payload", "epl.asnd.sdo.cmd.write.by.index.data", FT_BYTES, BASE_HEX, NULL, 0x00, "", HFILL }}, { &hf_epl_asnd_sdo_cmd_read_by_index_data, { "Payload", "epl.asnd.sdo.cmd.read.by.index.data", FT_BYTES, BASE_HEX, NULL, 0x00, "", HFILL }}, }; /* Setup protocol subtree array */ static gint *ett[] = { &ett_epl, &ett_epl_seb, &ett_epl_el, &ett_epl_el_entry, &ett_epl_el_entry_type, &ett_epl_sdo_entry_type, }; /* Register the protocol name and description */ proto_epl = proto_register_protocol("ETHERNET Powerlink v2", "EPL", "epl"); /* Required function calls to register the header fields and subtrees used */ proto_register_field_array(proto_epl, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); /* tap-registration */ /* epl_tap = register_tap("epl");*/ } void proto_reg_handoff_epl(void) { dissector_handle_t epl_handle; epl_handle = create_dissector_handle(dissect_epl, proto_epl); dissector_add("ethertype", ETHERTYPE_EPL_V2, epl_handle); }