/* packet-homeplug.c * Routines for homeplug dissection * * Copyright 2006, Sebastien Tandel * * $Id$ * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 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 #include /* METYPE Values */ #define HOMEPLUG_MME_RCE 0x00 #define HOMEPLUG_MME_CER 0x01 #define HOMEPLUG_MME_RPS 0x07 #define HOMEPLUG_MME_PSR 0x08 #define HOMEPLUG_MME_NS 0x1A /* Bit mask Operation */ #define HOMEPLUG_MCTRL_RSVD 0x80 #define HOMEPLUG_MCTRL_NE 0x7F #define HOMEPLUG_MEHDR_MEV 0xE0 #define HOMEPLUG_MEHDR_METYPE 0x1F #define HOMEPLUG_NS_AC 0x80 #define HOMEPLUG_NS_ICID 0x7F #define HOMEPLUG_RCE_CEV 0xF0 #define HOMEPLUG_RCE_RSVD 0x0F #define HOMEPLUG_CER_CERV 0xF0 #define HOMEPLUG_CER_RSVD 0x0FE0 #define HOMEPLUG_CER_RXTMI 0x1F #define HOMEPLUG_CER_RATE 0x80 #define HOMEPLUG_CER_BP 0x40 #define HOMEPLUG_CER_VT11 0x0F #define HOMEPLUG_CER_RSVD2 0x80 #define HOMEPLUG_CER_NBDAS 0x7F /* Length of Network Statistics Response defines whether it is the Basic or * the Extended Response */ #define HOMEPLUG_NS_BASIC_LEN 187 #define HOMEPLUG_NS_EXT_LEN 199 /* forward reference */ void proto_reg_handoff_homeplug(void); static int proto_homeplug = -1; static int hf_homeplug_mctrl = -1; static int hf_homeplug_mctrl_reserved = -1; static int hf_homeplug_mctrl_ne = -1; static int hf_homeplug_mehdr = -1; static int hf_homeplug_mehdr_mev = -1; static int hf_homeplug_mehdr_metype = -1; static int hf_homeplug_melen = -1; static int hf_homeplug_mme = -1; /* Request Channel Estimation */ static int hf_homeplug_rce = -1; static int hf_homeplug_rce_cev = -1; static int hf_homeplug_rce_rsvd = -1; /* Channel Estimation Response */ static int hf_homeplug_cer = -1; static int hf_homeplug_cer_cerv = -1; static int hf_homeplug_cer_rsvd1 = -1; static int hf_homeplug_cer_rxtmi = -1; static int hf_homeplug_cer_vt = -1; static int hf_homeplug_cer_rate = -1; static int hf_homeplug_cer_bp = -1; static int hf_homeplug_cer_mod = -1; static int hf_homeplug_cer_vt11 = -1; static int hf_homeplug_cer_rsvd2 = -1; static int hf_homeplug_cer_nbdas = -1; static int hf_homeplug_cer_bda = -1; /* Request Parameters and Statistics */ static int hf_homeplug_rps = -1; /* Parameters and Statistics Response */ static int hf_homeplug_psr = -1; static int hf_homeplug_psr_txack = -1; static int hf_homeplug_psr_txnack = -1; static int hf_homeplug_psr_txfail = -1; static int hf_homeplug_psr_txcloss = -1; static int hf_homeplug_psr_txcoll = -1; static int hf_homeplug_psr_txca3lat = -1; static int hf_homeplug_psr_txca2lat = -1; static int hf_homeplug_psr_txca1lat = -1; static int hf_homeplug_psr_txca0lat = -1; static int hf_homeplug_psr_rxbp40 = -1; /* Network Statistics */ /* Basic */ static int hf_homeplug_ns = -1; static int hf_homeplug_ns_netw_ctrl_ac = -1; static int hf_homeplug_ns_netw_ctrl_icid = -1; static int hf_homeplug_ns_netw_ctrl_icid_rsvd = -1; static int hf_homeplug_ns_bytes40_robo = -1; static int hf_homeplug_ns_fails_robo = -1; static int hf_homeplug_ns_drops_robo = -1; static int hf_homeplug_ns_netw_da = -1; static int hf_homeplug_ns_bytes40 = -1; static int hf_homeplug_ns_fails = -1; static int hf_homeplug_ns_drops = -1; /* array of 15 elements */ /* static int hf_homeplug_ns_bytes40_1 = -1; static int hf_homeplug_ns_bytes40_1 */ /* Extended */ /* array of 6 elements */ /* static int hf_homeplug_ns_tx_bfr_0_state = -1;*/ static gint ett_homeplug = -1; static gint ett_homeplug_mctrl = -1; static gint ett_homeplug_mehdr = -1; static gint ett_homeplug_rce = -1; static gint ett_homeplug_cer = -1; static gint ett_homeplug_rps = -1; static gint ett_homeplug_psr = -1; static gint ett_homeplug_ns = -1; static gint ett_homeplug_tone = -1; static guint8 homeplug_ne = 0; static guint8 homeplug_melen = 0; static guint8 homeplug_metype = 0; static guint32 homeplug_offset = 0; /* IC_ID Values */ #define HOMEPLUG_NS_ICID5130A1 0x00 #define HOMEPLUG_NS_ICID51X1USB 0x01 #define HOMEPLUG_NS_ICID51X1PHY 0x02 #define HOMEPLUG_NS_ICID51X1HOST 0x03 #define HOMEPLUG_NS_ICID5130A2 0x04 #define HOMEPLUG_NS_ICID_RSVD1 0x05 #define HOMEPLUG_NS_ICID_RSVD2 0x06 #define HOMEPLUG_NS_ICID_RSVD3 0x07 /* ICID Bit Mask */ #define HOMEPLUG_NS_ICID_MASK 0x07 #define HOMEPLUG_NS_ICID_RSVD_MASK 0x78 /* string values in function of IC_ID values */ static const value_string homeplug_ns_icid_vals[] = { { HOMEPLUG_NS_ICID5130A1, "INT5130A1" }, { HOMEPLUG_NS_ICID51X1USB, "INT51X1 (USB Option)" }, { HOMEPLUG_NS_ICID51X1PHY, "INT51X1 (PHY Option)" }, { HOMEPLUG_NS_ICID51X1HOST, "INT51X1 (Host/DTE Option)" }, { HOMEPLUG_NS_ICID5130A2, "INT5130A2" }, { HOMEPLUG_NS_ICID_RSVD1, "Reserved"}, { HOMEPLUG_NS_ICID_RSVD2, "Reserved"}, { HOMEPLUG_NS_ICID_RSVD3, "Reserved"}, { 0, NULL } }; /* Modulation Method Bit Mask */ #define HOMEPLUG_CER_MOD_MASK 0x30 /* Modulation Method Values */ #define HOMEPLUG_CER_MOD_ROBO 0x00 #define HOMEPLUG_CER_MOD_DBPSK 0x01 #define HOMEPLUG_CER_MOD_DQPSK 0x02 #define HOMEPLUG_CER_MOD_RSVD 0x03 /* string values in function of Modulation Method Values */ static const value_string homeplug_cer_mod_vals[] = { { HOMEPLUG_CER_MOD_ROBO, "ROBO Modulation"}, { HOMEPLUG_CER_MOD_DBPSK, "DBPSK Modulation"}, { HOMEPLUG_CER_MOD_DQPSK, "DQPSK Modulation"}, { HOMEPLUG_CER_MOD_RSVD, "Reserved"}, { 0, NULL} }; #define HOMEPLUG_MCTRL_LEN 1 #define HOMEPLUG_MEHDR_LEN 1 #define HOMEPLUG_MELEN_LEN 1 void proto_register_homeplug(void) { static hf_register_info hf[] = { /* MAC Control Field */ { &hf_homeplug_mctrl, { "MAC Control Field", "homeplug.mctrl", FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Control Field", HFILL } }, { &hf_homeplug_mctrl_reserved, { "Reserved", "homeplug.mctrl.rsvd", FT_NONE, BASE_DEC, NULL, HOMEPLUG_MCTRL_RSVD, "Reserved", HFILL } }, { &hf_homeplug_mctrl_ne, { "Number of MAC Data Entries", "homeplug.mctrl.ne", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_MCTRL_NE, "Number of MAC Data Entries", HFILL } }, /* MAC Entry Header */ { &hf_homeplug_mehdr, { "MAC Management Entry Header", "homeplug.mehdr", FT_NONE, BASE_DEC, NULL, 0x0, "MAC Management Entry Header", HFILL } }, { &hf_homeplug_mehdr_mev, { "MAC Entry Version", "homeplug.mehdr.mev", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_MEHDR_MEV, "MAC Entry Version", HFILL } }, { &hf_homeplug_mehdr_metype, { "MAC Entry Type", "homeplug.mehdr.metype", FT_UINT8, BASE_HEX, NULL, HOMEPLUG_MEHDR_METYPE, "MAC Entry Type", HFILL } }, /* MAC Entry Len */ { &hf_homeplug_melen, { "MAC Management Entry Length", "homeplug.melen", FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Management Entry Length", HFILL } }, /* MAC Management Entry */ { &hf_homeplug_mme, { "MAC Management Entry Data", "homeplug.mmentry", FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Management Entry Data", HFILL } }, /* Request Channel Estimation */ { &hf_homeplug_rce, { "Request Channel Estimation", "homeplug.rce", FT_NONE, BASE_DEC, NULL, 0x0, "Request Channel Estimation", HFILL } }, { &hf_homeplug_rce_cev, { "Channel Estimation Version", "homeplug.rce.cev", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_RCE_CEV, "Channel Estimation Version", HFILL } }, { &hf_homeplug_rce_rsvd, { "Reserved", "homeplug.rce.rsvd", FT_NONE, BASE_DEC, NULL, HOMEPLUG_RCE_RSVD, "Reserved", HFILL } }, /* Channel Estimation Response */ { &hf_homeplug_cer, { "Channel Estimation Response", "homeplug.cer", FT_NONE, BASE_DEC, NULL, 0x0, "Channel Estimation Response", HFILL } }, { &hf_homeplug_cer_cerv, { "Channel Estimation Response Version", "homeplug.cer.cerv", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_CERV, "Channel Estimation Response Version", HFILL } }, { &hf_homeplug_cer_rsvd1, { "Reserved", "homeplug.cer.rsvd1", FT_NONE, BASE_DEC, NULL, HOMEPLUG_CER_RSVD, "Reserved", HFILL } }, { &hf_homeplug_cer_rxtmi, { "Receive Tone Map Index", "homeplug.cer.rxtmi", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RXTMI, "Receive Tone Map Index", HFILL } }, /* TODO must append vt[79-0] */ { &hf_homeplug_cer_vt, {"Valid Tone Flags", "homeplug.cer.vt", FT_UINT8, BASE_HEX, NULL, 0x0, "Valid Tone Flags", HFILL } }, { &hf_homeplug_cer_rate, { "FEC Rate", "homeplug.cer.rate", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RATE, "FEC Rate", HFILL } }, { &hf_homeplug_cer_bp, { "Bridge Proxy", "homeplug.cer.bp", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_BP, "Bridge Proxy", HFILL } }, { &hf_homeplug_cer_mod, { "Modulation Method", "homeplug.cer.mod", FT_UINT8, BASE_DEC, VALS(&homeplug_cer_mod_vals), HOMEPLUG_CER_MOD_MASK, "Modulation Method", HFILL } }, { &hf_homeplug_cer_vt11, { "Valid Tone Flags [83-80]", "homeplug.cer.vt11", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_VT11, "Valid Tone Flags [83-80]", HFILL } }, { &hf_homeplug_cer_rsvd2, { "Reserved", "homeplug.cer.rsvd2", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RSVD2, "Reserved", HFILL } }, { &hf_homeplug_cer_nbdas, { "Number Bridged Destination Addresses", "homeplug.cer.nbdas", FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_NBDAS, "Number Bridged Destination Addresses", HFILL } }, { &hf_homeplug_cer_bda, { "Bridged Destination Address", "homeplug.cer.bda", FT_ETHER, BASE_HEX, NULL, 0x0, "Bridged Destination Address", HFILL } }, /* Request Parameters and Statistics */ { &hf_homeplug_rps, { "Request Parameters and Statistics", "homeplug.rps", FT_NONE, BASE_DEC, NULL, 0x0, "Request Parameters and Statistics", HFILL } }, /* Parameters and Statistics Response */ { &hf_homeplug_psr, { "Parameters and Statistics Response", "homeplug.psr", FT_NONE, BASE_DEC, NULL, 0x0, "Parameters and Statistics Response", HFILL } }, { &hf_homeplug_psr_txack, { "Transmit ACK Counter", "homeplug.psr.txack", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit ACK Counter", HFILL } }, { &hf_homeplug_psr_txnack, { "Transmit NACK Counter", "homeplug.psr.txnack", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit NACK Counter", HFILL } }, { &hf_homeplug_psr_txfail, { "Transmit FAIL Counter", "homeplug.psr.txfail", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit FAIL Counter", HFILL } }, { &hf_homeplug_psr_txcloss, { "Transmit Contention Loss Counter", "homeplug.psr.txcloss", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit Contention Loss Counter", HFILL } }, { &hf_homeplug_psr_txcoll, { "Transmit Collision Counter", "homeplug.psr.txcoll", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit Collision Counter", HFILL } }, { &hf_homeplug_psr_txca3lat, { "Transmit CA3 Latency Counter", "homeplug.psr.txca3lat", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA3 Latency Counter", HFILL } }, { &hf_homeplug_psr_txca2lat, { "Transmit CA2 Latency Counter", "homeplug.psr.txca2lat", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA2 Latency Counter", HFILL } }, { &hf_homeplug_psr_txca1lat, { "Transmit CA1 Latency Counter", "homeplug.psr.txca1lat", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA1 Latency Counter", HFILL } }, { &hf_homeplug_psr_txca0lat, { "Transmit CA0 Latency Counter", "homeplug.psr.txca0lat", FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA0 Latency Counter", HFILL } }, { &hf_homeplug_psr_rxbp40, { "Receive Cumulative Bytes per 40-symbol", "homeplug.psr.rxbp40", FT_UINT32, BASE_DEC, NULL, 0x0, "Receive Cumulative Bytes per 40-symbol", HFILL } }, /* Network Statistics Basic */ { &hf_homeplug_ns, { "Network Statistics Basic", "homeplug.ns", FT_NONE, BASE_DEC, NULL, 0x0, "Network Statistics Basic", HFILL } }, { &hf_homeplug_ns_netw_ctrl_ac, { "Action Control", "homeplug.ns.ac", FT_BOOLEAN, BASE_DEC, NULL, HOMEPLUG_NS_AC, "Action Control", HFILL } }, { &hf_homeplug_ns_netw_ctrl_icid, { "IC_ID", "homeplug.ns.icid", FT_UINT8, BASE_HEX, VALS(&homeplug_ns_icid_vals), HOMEPLUG_NS_ICID_MASK, "IC_ID", HFILL } }, { &hf_homeplug_ns_netw_ctrl_icid_rsvd, { "IC_ID Reserved", "homeplug.ns.icid", FT_NONE, BASE_DEC, NULL, 0x0, "IC_ID Reserved", HFILL } }, { &hf_homeplug_ns_bytes40_robo, { "Bytes in 40 symbols in ROBO", "homeplug.ns.bytes40_robo", FT_UINT16, BASE_DEC, NULL, 0x0, "Bytes in 40 symbols in ROBO", HFILL } }, { &hf_homeplug_ns_fails_robo, { "Fails Received in ROBO", "homeplug.ns.fails_robo", FT_UINT16, BASE_DEC, NULL, 0x0, "Fails Received in ROBO", HFILL } }, { &hf_homeplug_ns_drops_robo, { "Frame Drops in ROBO", "homeplug.ns.drops_robo", FT_UINT16, BASE_DEC, NULL, 0x0, "Frame Drops in ROBO", HFILL } }, /* TODO NETW_DA1 ... */ { &hf_homeplug_ns_netw_da, { "Address of Network DA", "homeplug.ns.netw_da", FT_ETHER, BASE_HEX, NULL, 0x0, "Address of Network DA", HFILL } }, { &hf_homeplug_ns_bytes40, { "Bytes in 40 symbols", "homeplug.ns.bytes40", FT_UINT16, BASE_DEC, NULL, 0x0, "Bytes in 40 symbols", HFILL } }, { &hf_homeplug_ns_fails, { "Fails Received", "homeplug.ns.fails", FT_UINT16, BASE_DEC, NULL, 0x0, "Fails Received", HFILL } }, { &hf_homeplug_ns_drops, { "Frame Drops", "homeplug.ns.drops", FT_UINT16, BASE_DEC, NULL, 0x0, "Frame Drops", HFILL } } /* TODO Network Statistics Extended */ }; /* Setup protocol subtree array */ static gint *ett[] = { &ett_homeplug, &ett_homeplug_mctrl, &ett_homeplug_mehdr, &ett_homeplug_rce, &ett_homeplug_cer, &ett_homeplug_rps, &ett_homeplug_psr, &ett_homeplug_ns, &ett_homeplug_tone }; proto_homeplug = proto_register_protocol( "HomePlug protocol", /* Name */ "HomePlug", /* Short Name */ "homeplug" /* Abbrev */ ); proto_register_field_array(proto_homeplug, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } /* Dissection of MCTRL */ static void dissect_homeplug_mctrl(ptvcursor_t * cursor) { proto_item * it = NULL; if (!ptvcursor_tree(cursor)) return; it = ptvcursor_add_no_advance(cursor, hf_homeplug_mctrl, 1, FALSE); homeplug_ne = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)) & HOMEPLUG_MCTRL_NE; ptvcursor_push_subtree(cursor, it, ett_homeplug_mctrl); ptvcursor_add_no_advance(cursor, hf_homeplug_mctrl_reserved, 1, FALSE); ptvcursor_add(cursor, hf_homeplug_mctrl_ne, 1, FALSE); ptvcursor_pop_subtree(cursor); } /* Dissection of MEHDR */ static void dissect_homeplug_mehdr(ptvcursor_t * cursor) { proto_item * it = NULL; if (!ptvcursor_tree(cursor)) return; it = ptvcursor_add_no_advance(cursor, hf_homeplug_mehdr, 0, FALSE); homeplug_metype = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)) & HOMEPLUG_MEHDR_METYPE; ptvcursor_push_subtree(cursor, it, ett_homeplug_mehdr); ptvcursor_add_no_advance(cursor, hf_homeplug_mehdr_mev, 1, FALSE); ptvcursor_add(cursor, hf_homeplug_mehdr_metype, 1, FALSE); ptvcursor_pop_subtree(cursor); } /* dissection of MELEN */ static void dissect_homeplug_melen(ptvcursor_t * cursor) { if (!ptvcursor_tree(cursor)) return; homeplug_melen = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)); ptvcursor_add(cursor, hf_homeplug_melen, 1, FALSE); } /* Dissection of Request Channel Estimation MME */ static void dissect_homeplug_rce(ptvcursor_t * cursor) { proto_item * it = NULL; if (!ptvcursor_tree(cursor)) return; it = ptvcursor_add_no_advance(cursor, hf_homeplug_rce, homeplug_melen, FALSE); ptvcursor_push_subtree(cursor, it, ett_homeplug_rce); ptvcursor_add_no_advance(cursor, hf_homeplug_rce_cev, 1, FALSE); ptvcursor_add(cursor, hf_homeplug_rce_rsvd, 1, FALSE); ptvcursor_pop_subtree(cursor); } /* Dissection of Channel Estimation Response MME */ static void dissect_homeplug_cer(ptvcursor_t * cursor) { proto_item * it = NULL; guint8 iTone = 0; guint8 BP = 0; guint8 iNBDA = 0; if (!ptvcursor_tree(cursor)) return; it = ptvcursor_add_no_advance(cursor, hf_homeplug_cer_cerv, homeplug_melen, FALSE); ptvcursor_push_subtree(cursor, it, ett_homeplug_cer); ptvcursor_add_no_advance(cursor, hf_homeplug_cer_cerv, 1, FALSE); ptvcursor_add(cursor, hf_homeplug_cer_rsvd1, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_cer_rxtmi, 1, FALSE); for (;iTone < 10; iTone++) { ptvcursor_add(cursor, hf_homeplug_cer_vt, 1, FALSE); } ptvcursor_add_no_advance(cursor, hf_homeplug_cer_rate, 1, FALSE); ptvcursor_add_no_advance(cursor, hf_homeplug_cer_bp, 1, FALSE); BP = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)) & HOMEPLUG_CER_BP; ptvcursor_add_no_advance(cursor, hf_homeplug_cer_mod, 1, FALSE); ptvcursor_add(cursor, hf_homeplug_cer_vt11, 1, FALSE); ptvcursor_add_no_advance(cursor, hf_homeplug_cer_rsvd2, 1, FALSE); if (BP) { iNBDA = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)) & HOMEPLUG_CER_NBDAS; ptvcursor_add(cursor, hf_homeplug_cer_nbdas, 1, FALSE); /* TODO : Check on iNBDA! INT51X1 up to 16 dba. But up to 32 for INT51X1 (Host/DTE) */ for (;iNBDA > 0; iNBDA--) { ptvcursor_add(cursor, hf_homeplug_cer_bda, 6, FALSE); } } ptvcursor_pop_subtree(cursor); } /* Dissection of Request Parameters and Statistics MME */ static void dissect_homeplug_rps(ptvcursor_t * cursor) { if (!ptvcursor_tree(cursor)) return; ptvcursor_add(cursor, hf_homeplug_rps, 4, FALSE); } /* Dissection of Parameters and Statistics Response MME */ static void dissect_homeplug_psr(ptvcursor_t * cursor) { proto_item * it = NULL; if (!ptvcursor_tree(cursor)) return; it = ptvcursor_add_no_advance(cursor, hf_homeplug_psr, homeplug_melen, FALSE); ptvcursor_push_subtree(cursor, it, ett_homeplug_psr); ptvcursor_add(cursor, hf_homeplug_psr_txack, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_txnack, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_txfail, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_txcloss, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_txcoll, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_txca3lat, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_txca2lat, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_txca1lat, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_txca0lat, 2, FALSE); ptvcursor_add(cursor, hf_homeplug_psr_rxbp40, 4, FALSE); ptvcursor_pop_subtree(cursor); } /* Dissection of the Network Statistic MME */ static void dissect_homeplug_ns(ptvcursor_t * cursor) { guint8 homeplug_ns_icid_rsvd = 0; guint8 iTone = 0; guint16 ns_bytes40= 0; guint64 newt_da= 0; #define NEWT_DA_INEXISTANT G_GINT64_CONSTANT(010000000000U) if (!ptvcursor_tree(cursor)) return; /* TODO : test length of the MME : differentiation of NS Basic and Extended */ ptvcursor_add_with_subtree(cursor, hf_homeplug_ns, SUBTREE_UNDEFINED_LENGTH, FALSE, ett_homeplug_ns); /*it = ptvcursor_add_no_advance(cursor, hf_homeplug_ns, homeplug_melen, FALSE); ptvcursor_push_subtree(cursor, it, ett_homeplug_ns);*/ ptvcursor_add_no_advance(cursor, hf_homeplug_ns_netw_ctrl_ac, 1, FALSE); homeplug_ns_icid_rsvd = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)) & HOMEPLUG_NS_ICID_RSVD_MASK; if (homeplug_ns_icid_rsvd) ptvcursor_add(cursor, hf_homeplug_ns_netw_ctrl_icid_rsvd, 1, FALSE); else ptvcursor_add(cursor, hf_homeplug_ns_netw_ctrl_icid, 1, FALSE); ptvcursor_add_no_advance(cursor, hf_homeplug_ns_bytes40_robo, 2, TRUE); ns_bytes40 = tvb_get_letohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)); proto_tree_add_text(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), 2, "MHz : %.3f", (float)(ns_bytes40)/42); ptvcursor_advance(cursor, 2); ptvcursor_add(cursor, hf_homeplug_ns_fails_robo, 2, TRUE); ptvcursor_add(cursor, hf_homeplug_ns_drops_robo, 2, TRUE); while (iTone < 15) { newt_da = ((gint64)tvb_get_ntoh24(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor))) << 24; newt_da |= tvb_get_ntoh24(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)+3); if (newt_da != NEWT_DA_INEXISTANT) { ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_homeplug_tone, "Tone Map #%d", iTone+1); ptvcursor_add(cursor, hf_homeplug_ns_netw_da, 6, FALSE); ptvcursor_add_no_advance(cursor, hf_homeplug_ns_bytes40, 2, TRUE); ns_bytes40 = tvb_get_letohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)); proto_tree_add_text(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), 2, "MHz : %.3f", (float)(ns_bytes40)/42); ptvcursor_advance(cursor, 2); ptvcursor_add(cursor, hf_homeplug_ns_fails, 2, TRUE); ptvcursor_add(cursor, hf_homeplug_ns_drops, 2, TRUE); ptvcursor_pop_subtree(cursor); } else proto_tree_add_text(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), 12, "Tone Map #%d does not exist", iTone+1); iTone++; } ptvcursor_pop_subtree(cursor); } static void dissect_homeplug_mme(ptvcursor_t * cursor, packet_info * pinfo) { switch(homeplug_metype) { case HOMEPLUG_MME_RCE: if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_set_str(pinfo->cinfo, COL_INFO, "Request Channel Estimation"); } dissect_homeplug_rce(cursor); break; case HOMEPLUG_MME_CER: if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_set_str(pinfo->cinfo, COL_INFO, "Channel Estimation Response"); } dissect_homeplug_cer(cursor); break; case HOMEPLUG_MME_RPS: if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_set_str(pinfo->cinfo, COL_INFO, "Request Parameters and Statistics"); } dissect_homeplug_rps(cursor); break; case HOMEPLUG_MME_PSR: if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_set_str(pinfo->cinfo, COL_INFO, "Parameters and Statistics Response"); } dissect_homeplug_psr(cursor); break; case HOMEPLUG_MME_NS: if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_set_str(pinfo->cinfo, COL_INFO, "Network Statistics"); } dissect_homeplug_ns(cursor); break; } } #define TVB_LEN_GREATEST 1 #define TVB_LEN_UNDEF 0 #define TVB_LEN_SHORTEST -1 static int check_tvb_length(ptvcursor_t *cursor, const gint length) { if (!cursor) return TVB_LEN_UNDEF; if (tvb_reported_length_remaining(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)) < length) return TVB_LEN_SHORTEST; return TVB_LEN_GREATEST; } static void dissect_homeplug(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { proto_item * it= NULL; proto_tree * homeplug_tree= NULL; ptvcursor_t * cursor= NULL; if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "HomePlug"); /* Clear out stuff in the info column */ if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_set_str(pinfo->cinfo, COL_INFO, "MAC Management"); } homeplug_offset = 0; if (tree) { it = proto_tree_add_item(tree, proto_homeplug, tvb, homeplug_offset, -1, FALSE); homeplug_tree = proto_item_add_subtree(it, ett_homeplug); cursor = ptvcursor_new(homeplug_tree, tvb, 0); } /* We do not have enough data to read mctrl field stop the dissection */ if (check_tvb_length(cursor, HOMEPLUG_MCTRL_LEN) != TVB_LEN_SHORTEST) { dissect_homeplug_mctrl(cursor); /** homeplug_ne indicates the number of MME entries. This field is fetched * from MCTRL. */ for (; homeplug_ne > 0; homeplug_ne--) { /* Check we have enough data in tvb to read MEHDR */ if (check_tvb_length(cursor, HOMEPLUG_MEHDR_LEN) == TVB_LEN_SHORTEST) break; dissect_homeplug_mehdr(cursor); /* Check we have enough data in tvb to read MELEN */ if (check_tvb_length(cursor, HOMEPLUG_MELEN_LEN) == TVB_LEN_SHORTEST) break; dissect_homeplug_melen(cursor); dissect_homeplug_mme(cursor, pinfo); } } if (cursor) ptvcursor_free(cursor); } static dissector_handle_t homeplug_handle; void proto_reg_handoff_homeplug(void) { static gboolean initialised = FALSE; if (!initialised) { homeplug_handle = create_dissector_handle(dissect_homeplug, proto_homeplug); dissector_add("ethertype", ETHERTYPE_HOMEPLUG, homeplug_handle); initialised = TRUE; } }