/* packet-cfm.c * Routines for CFM EOAM dissection * Copyright 2007, Keith Mercer * Copyright 2011, Peter Nahas * Copyright 2012, Wim Leflere * Copyright 2013, Andreas Urke * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ /* This code is based on the following documents: * - IEEE 802.1Q-2022 - IEEE Standard for Local and metropolitan area networks — Bridges and Bridged Networks * - ITU-T Rec. G.8013/Y.1731 (08/2015) - OAM functions and mechanisms for Ethernet-based networks * - ITU-T Rec. G.8031/Y.1342 (01/2015) - Ethernet linear protection switching * - ITU-T Rec. G.8032/Y.1344 (03/2020) - Ethernet ring protection switching * - ITU-T Rec. G.8113/Y.1372 (04/2016) - OAM mechanisms for MPLS-TP in packet transport networks * - IEEE 802.1AB-2016 - IEEE Standard for Local and metropolitan area networks — Station and Media Access Control Connectivity Discovery */ #include "config.h" #include #include #include #include #include #include "packet-mpls.h" /* Value declarations for CFM EOAM dissection */ /* CFM Common header */ #define CFM_COMMON_HEADER_LEN 4 #define CFM_LEVEL_VERSION_OFFSET 0 #define CFM_LEVEL_MASK 0xE0 #define CFM_LEVEL_SHIFT 5 #define CFM_VERSION_MASK 0x1F #define CFM_VERSION_SHIFT 0 #define CFM_OPCODE_OFFSET 1 #define CFM_FLAGS_OFFSET 2 #define CFM_1ST_TLV_OFFSET 3 /* Defined by IEEE 802.1Q */ #define IEEE8021 0x00 #define CCM 0x01 #define LBR 0x02 #define LBM 0x03 #define LTR 0x04 #define LTM 0X05 #define RFM 0x06 #define SFM 0x07 /* Defined by ITU-T G.8013/Y.1731 */ #define GNM 0x20 #define AIS 0x21 #define LCK 0x23 #define TST 0x25 #define APS 0x27 #define RAPS 0x28 #define MCC 0x29 #define LMM 0x2B #define LMR 0x2A #define ODM 0x2D #define DMM 0x2F #define DMR 0x2E #define EXM 0x31 #define EXR 0x30 #define VSM 0x33 #define VSR 0x32 #define CSF 0x34 #define OSL 0x35 #define SLM 0x37 #define SLR 0x36 /* Defined by IEEE 802.1Q */ #define END_TLV 0x00 #define SENDER_ID_TLV 0x01 #define PORT_STAT_TLV 0x02 #define DATA_TLV 0x03 #define INTERF_STAT_TLV 0x04 #define REPLY_ING_TLV 0x05 #define REPLY_EGR_TLV 0x06 #define LTM_EGR_ID_TLV 0x07 #define LTR_EGR_ID_TLV 0x08 #define PPB_TE_MIP_TLV 0x09 #define DATA_PART1_TLV 0x0A #define DATA_PART2_TLV 0x0B #define TRUNC_DATA_TLV 0x0C // XXX - Does this TLV even exist? #define GNM_TLV 0x0D #define ORG_SPEC_TLV 0x1F /* Defined by ITU-T Y.1731 */ #define TEST_TLV 0x20 /* Defined by ITU-T Y.1372.1 */ #define TGT_MEP_MIP_ID_TLV 0x21 #define RPL_MEP_MIP_ID_TLV 0x22 #define REQ_MEP_ID_TLV 0x23 /* Defined by ITU-T Y.1731 */ #define TEST_ID_TLV 0x24 /* Sub-OpCode for GNM */ #define BNM 0x01 /* MAID values */ #define MD_NAME_FMT_RESVD 0 #define MD_NAME_FMT_NONE 1 #define MD_NAME_FMT_DOMAIN 2 #define MD_NAME_FMT_MAC_ID 3 #define MD_NAME_FMT_STRING 4 #define MA_NAME_FMT_RESVD 0 #define MA_NAME_FMT_PVID 1 #define MA_NAME_FMT_STRING 2 #define MA_NAME_FMT_ID 3 #define MA_NAME_FMT_VPN_ID 4 #define MA_NAME_FMT_ICC 32 #define MA_NAME_FMT_ICC_CC 33 /* R-APS values */ #define RAPS_REQ_ST_MASK 0xF0 #define RAPS_REQ_ST_SHIFT 4 #define RAPS_SUB_CODE_MASK 0x0F #define RAPS_SUB_CODE_SHIFT 0 #define RAPS_REQ_ST_NO_REQ 0 #define RAPS_REQ_ST_MAN_SW 7 #define RAPS_REQ_ST_SIG_FAIL 11 #define RAPS_REQ_ST_FCED_SW 13 #define RAPS_REQ_ST_EVENT 14 static const value_string opcode_type_name_vals[] = { { IEEE8021, "Reserved for IEEE 802.1" }, { CCM, "Continuity Check Message (CCM)" }, { LBR, "Loopback Reply (LBR)" }, { LBM, "Loopback Message (LBM)" }, { LTR, "Linktrace Reply (LTR)" }, { LTM, "Linktrace Message (LTM)" }, { RFM, "Reflected Frame Message (RFM)" }, { SFM, "Send Frame Message (SFM)" }, { GNM, "Generic Notification Message (GNM)" }, { AIS, "Alarm Indication Signal (AIS)" }, { LCK, "Lock Signal (LCK)" }, { TST, "Test Signal (TST)" }, { APS, "Automatic Protection Switching (APS)" }, { RAPS, "Ring-Automatic Protection Switching (R-APS)" }, { MCC, "Maintenance Communication Channel (MCC)" }, { LMM, "Loss Measurement Message (LMM)" }, { LMR, "Loss Measurement Reply (LMR)" }, { ODM, "One Way Delay Measurement (1DM)" }, { DMM, "Delay Measurement Message (DMM)" }, { DMR, "Delay Measurement Reply (DMR)" }, { EXM, "Experimental OAM Message (EXM)" }, { EXR, "Experimental OAM Reply (EXR)" }, { VSM, "Vendor Specific Message (VSM)" }, { VSR, "Vendor Specific Reply (VSR)" }, { CSF, "Client Signal Fail (CSF)" }, { OSL, "One Way Synthetic Loss Measurement (1SL)" }, { SLM, "Synthetic Loss Message (SLM)" }, { SLR, "Synthetic Loss Reply (SLR)" }, { 0, NULL } }; static const value_string tlv_type_field_vals[] = { { END_TLV, "End TLV" }, { SENDER_ID_TLV, "Sender ID TLV" }, { PORT_STAT_TLV, "Port Status TLV" }, { DATA_TLV, "Data TLV" }, { INTERF_STAT_TLV, "Interface Status TLV" }, { REPLY_ING_TLV, "Reply Ingress TLV" }, { REPLY_EGR_TLV, "Reply Egress TLV" }, { LTM_EGR_ID_TLV, "LTM Egress Identifier TLV" }, { LTR_EGR_ID_TLV, "LTR Egress Identifier TLV" }, { PPB_TE_MIP_TLV, "PBB-TE MIP TLV" }, { DATA_PART1_TLV, "Data Part 1 TLV" }, { DATA_PART2_TLV, "Data Part 2 TLV" }, { TRUNC_DATA_TLV, "Truncated Data TLV" }, { GNM_TLV, "Generic Notification Message TLV" }, { ORG_SPEC_TLV, "Organizational-Specific TLV" }, { TEST_TLV, "Test TLV" }, { TGT_MEP_MIP_ID_TLV, "Target MEP/MIP ID TLV" }, { RPL_MEP_MIP_ID_TLV, "Replying MEP/MIP ID TLV" }, { REQ_MEP_ID_TLV, "Requesting MEP ID TLV" }, { TEST_ID_TLV, "Test ID TLV" }, { 0, NULL } }; static const value_string md_name_format_type_vals[] = { { MD_NAME_FMT_RESVD, "Reserved for IEEE 802.1" }, { MD_NAME_FMT_NONE, "No Maintenance Domain Name present" }, { MD_NAME_FMT_DOMAIN, "Domain Name-based string" }, { MD_NAME_FMT_MAC_ID, "MAC address + 2-octet integer" }, { MD_NAME_FMT_STRING, "Character String" }, { 0, NULL } }; static const value_string ma_name_format_type_vals[] = { // IEEE 802.1Q { MA_NAME_FMT_RESVD, "Reserved for IEEE 802.1" }, { MA_NAME_FMT_PVID, "Primary VID" }, { MA_NAME_FMT_STRING, "Character String" }, { MA_NAME_FMT_ID, "2-octet integer" }, { MA_NAME_FMT_VPN_ID, "RFC 2685 VPN ID" }, // Y.1731 Annex A { MA_NAME_FMT_ICC, "ICC-based Format" }, { MA_NAME_FMT_ICC_CC, "ICC and CC based Format" }, { 0, NULL } }; static const value_string ccm_interval_field_encoding_vals[] = { { 0, "invalid" }, { 1, "Trans Int 3.33ms, max Lifetime 11.66ms, min Lifetime 10.83ms" }, { 2, "Trans Int 10ms, max Lifetime 35ms, min Lifetime 32.5ms" }, { 3, "Trans Int 100ms, max Lifetime 350ms, min Lifetime 325ms" }, { 4, "Trans Int 1s, max Lifetime 3.5s, min Lifetime 3.25s" }, { 5, "Trans Int 10s, max Lifetime 35s, min Lifetime 32.5s" }, { 6, "Trans Int 1min, max Lifetime 3.5min, min Lifetime 3.25min" }, { 7, "Trans Int 10min, max Lifetime 35min, min Lifetime 32.5min" }, { 0, NULL } }; static const value_string relay_action_type_vals[] = { { 1, "RlyHit" }, { 2, "RlyFDB" }, { 3, "RlyMPDB" }, { 0, NULL } }; static const value_string ais_lck_period_type_vals[] = { { 0, "Invalid Value for AIS/LCK PDU's" }, { 1, "Invalid Value for AIS/LCK PDU's" }, { 2, "Invalid Value for AIS/LCK PDU's" }, { 3, "Invalid Value for AIS/LCK PDU's" }, { 4, "1 frame per second" }, { 5, "Invalid Value for AIS/LCK PDU's" }, { 6, "1 frame per minute" }, { 7, "Invalid Value for AIS/LCK PDU's" }, { 0, NULL } }; static const value_string sender_id_tlv_chassis_id_subtype_vals[] = { { 1, "Chassis component" }, { 2, "Interface alias" }, { 3, "Port component" }, { 4, "MAC address" }, { 5, "Network address" }, { 6, "Interface name" }, { 7, "Locally assigned" }, { 0, NULL } }; static const value_string port_stat_tlv_vals[] = { { 1, "psBlocked" }, { 2, "psUp" }, { 0, NULL } }; static const value_string interface_stat_tlv_vals[] = { { 1, "isUp" }, { 2, "isDown" }, { 3, "isTesting" }, { 4, "isUnknown" }, { 5, "isDormant" }, { 6, "isNotPresent" }, { 7, "isLowerLayerDown" }, { 0, NULL } }; static const value_string reply_ingress_tlv_vals[] = { { 1, "IngOK" }, { 2, "IngDown" }, { 3, "IngBlocked" }, { 4, "IngVID" }, { 0, NULL } }; static const value_string reply_egress_tlv_vals[] = { { 1, "EgrOK" }, { 2, "EgrDown" }, { 3, "EgrBlocked" }, { 4, "EgrVID" }, { 0, NULL } }; static const value_string aps_request_state_vals[] = { { 0, "No request" }, { 1, "Do not revert" }, { 2, "Reverse request" }, { 3, "Unknown" }, { 4, "Exercise" }, { 5, "Wait to restore" }, { 6, "Depreciated" }, { 7, "Manual switch" }, { 8, "Unknown" }, { 9, "Signal degrade" }, { 10, "Unknown" }, { 11, "Signal fail for working" }, { 12, "Unknown" }, { 13, "Forced switch" }, { 14, "Signal fail on protection" }, { 15, "Lockout of protection" }, { 0, NULL } }; static const true_false_string tfs_aps_protection_type_A = { "APS channel", "No APS channel" }; static const true_false_string tfs_aps_protection_type_B = { "1:1 (no permanent bridge)", "1+1 (permanent bridge)" }; static const true_false_string tfs_aps_protection_type_D = { "Bidirectional switching", "Unidirectional switching" }; static const true_false_string tfs_aps_protection_type_R = { "Revertive operation", "Non-revertive operation" }; static const value_string aps_requested_signal_values[] = { { 0, "Null" }, { 1, "Normal traffic" }, { 0, NULL } }; static const value_string aps_bridged_signal_values[] = { { 0, "Null" }, { 1, "Normal traffic" }, { 0, NULL } }; static const value_string aps_bridge_type_values[] = { { 0, "Selector" }, { 1, "Broadcast" }, { 0, NULL } }; static const value_string raps_request_state_values[] = { { RAPS_REQ_ST_NO_REQ, "No Request" }, { RAPS_REQ_ST_MAN_SW, "Manual Switch" }, { RAPS_REQ_ST_SIG_FAIL, "Signal Fail" }, { RAPS_REQ_ST_FCED_SW, "Forced Switch" }, { RAPS_REQ_ST_EVENT, "Event" }, { 0, NULL } }; static const value_string rasp_event_subcode_vals[] = { { 0, "Flush Request" }, { 0, NULL } }; static const true_false_string tfs_rasp_rpl_blocked = { "Blocked", "Not Blocked" }; static const true_false_string tfs_rasp_dnf = { "Do Not Flush DB", "May Flush DB" }; static const true_false_string tfs_rasp_bpr = { "Ring link 1", "Ring link 0" }; static const value_string gnm_sub_opcode_type_name_vals[] = { { BNM, "Bandwidth Notification Message" }, { 0, NULL } }; static const value_string cfm_bnm_flags_period_vals[] = { { 0, "Invalid" }, { 1, "For further study" }, { 2, "For further study" }, { 3, "For further study" }, { 4, "1s" }, { 5, "10s" }, { 6, "1 min" }, { 7, "Invalid" }, { 0, NULL } }; static const value_string cfm_csf_flags_type_vals[] = { { 0, "LOS" }, { 1, "FDI/AIS" }, { 2, "RDI" }, { 3, "DCI" }, { 0, NULL } }; static const value_string cfm_csf_flags_period_vals[] = { { 0, "Invalid" }, { 1, "For further study" }, { 2, "For further study" }, { 3, "For further study" }, { 4, "1s" }, { 5, "For further study" }, { 6, "1 min" }, { 7, "For further study" }, { 0, NULL } }; static const true_false_string tfs_lmm_lmr_type = { "Proactive", "On-demand" }; static const true_false_string tfs_odm_dmm_dmr_type = { "Proactive", "On-demand" }; static const value_string test_tlv_pattern_type_vals[] = { { 0, "Null signal without CRC-32" }, { 1, "Null signal with CRC-32" }, { 2, "PRBS (2.e-31 -1), without CRC-32" }, { 3, "PRBS (2.e-31 -1), with CRC-32" }, { 0, NULL } }; static const value_string mep_mip_id_tlv_subtype_vals[] = { { 0x00, "Discovery ingress/node MEP/MIP" }, { 0x01, "Discovery egress MEP/MIP" }, { 0x02, "MEP ID" }, { 0x03, "MIP ID" }, { 0, NULL } }; static const value_string req_mep_id_tlv_lb_vals[] = { { 0x00, "LBM PDU" }, { 0x01, "LBR PDU" }, { 0, NULL } }; void proto_register_cfm(void); void proto_reg_handoff_cfm(void); static int proto_cfm = -1; static int hf_cfm_md_level = -1; static int hf_cfm_version = -1; static int hf_cfm_opcode = -1; static int hf_cfm_flags = -1; static int hf_cfm_flags_Reserved = -1; static int hf_cfm_first_tlv_offset = -1; static int hf_cfm_mep_id = -1; static int hf_cfm_maid = -1; static int hf_cfm_maid_md_name_format = -1; static int hf_cfm_maid_md_name_length = -1; static int hf_cfm_maid_md_name_string = -1; static int hf_cfm_maid_md_name_hex = -1; static int hf_cfm_maid_md_name_mac = -1; static int hf_cfm_maid_md_name_mac_id = -1; static int hf_cfm_maid_ma_name_format = -1; static int hf_cfm_maid_ma_name_length = -1; static int hf_cfm_maid_ma_name_pvid = -1; static int hf_cfm_maid_ma_name_string = -1; static int hf_cfm_maid_ma_name_id = -1; static int hf_cfm_maid_ma_name_vpnid_oui = -1; static int hf_cfm_maid_ma_name_vpnid_index = -1; static int hf_cfm_maid_ma_name_icc_umc = -1; static int hf_cfm_maid_ma_name_cc = -1; static int hf_cfm_maid_ma_name_hex = -1; static int hf_cfm_maid_padding = -1; static int hf_cfm_ccm_pdu = -1; static int hf_cfm_ccm_flags_RDI = -1; static int hf_cfm_ccm_flags_Traffic = -1; static int hf_cfm_ccm_flags_Reserved = -1; static int hf_cfm_ccm_flags_Interval = -1; static int hf_cfm_ccm_seq_number = -1; static int hf_cfm_ccm_itu_t_y1731 = -1; static int hf_cfm_ccm_itu_TxFCf = -1; static int hf_cfm_ccm_itu_RxFCb = -1; static int hf_cfm_ccm_itu_TxFCb = -1; static int hf_cfm_ccm_itu_reserved = -1; static int hf_cfm_lbm_pdu = -1; static int hf_cfm_lbm_lbr_transaction_id = -1; static int hf_cfm_lbr_pdu = -1; static int hf_cfm_ltm_pdu = -1; static int hf_cfm_ltm_flags_UseFDBonly = -1; static int hf_cfm_ltm_flags_Reserved = -1; static int hf_cfm_ltm_ltr_transaction_id = -1; static int hf_cfm_ltm_ltr_ttl = -1; static int hf_cfm_ltm_orig_addr = -1; static int hf_cfm_ltm_targ_addr = -1; static int hf_cfm_ltr_pdu = -1; static int hf_cfm_ltr_flags_UseFDBonly = -1; static int hf_cfm_ltr_flags_FwdYes = -1; static int hf_cfm_ltr_flags_TerminalMEP = -1; static int hf_cfm_ltr_flags_Reserved = -1; static int hf_cfm_ltr_relay_action = -1; static int hf_cfm_rfm_pdu = -1; static int hf_cfm_rfm_transaction_id = -1; static int hf_cfm_sfm_pdu = -1; static int hf_cfm_sfm_transaction_id = -1; static int hf_cfm_gnm_pdu = -1; static int hf_cfm_gnm_unknown_flags = -1; static int hf_cfm_gnm_subopcode = -1; static int hf_cfm_bnm_flags_Reserved = -1; static int hf_cfm_bnm_flags_Period = -1; static int hf_cfm_bnm_pdu = -1; static int hf_cfm_bnm_nominal_bw = -1; static int hf_cfm_bnm_current_bw = -1; static int hf_cfm_bnm_port_id = -1; static int hf_cfm_ais_pdu = -1; static int hf_cfm_ais_flags_Reserved = -1; static int hf_cfm_ais_flags_Period = -1; static int hf_cfm_lck_pdu = -1; static int hf_cfm_lck_flags_Reserved = -1; static int hf_cfm_lck_flags_Period = -1; static int hf_cfm_tst_pdu = -1; static int hf_cfm_tst_sequence_num = -1; static int hf_cfm_aps_pdu = -1; static int hf_cfm_aps_req_st = -1; static int hf_cfm_aps_protection_type_A = -1; static int hf_cfm_aps_protection_type_B = -1; static int hf_cfm_aps_protection_type_D = -1; static int hf_cfm_aps_protection_type_R = -1; static int hf_cfm_aps_requested_signal = -1; static int hf_cfm_aps_bridged_signal = -1; static int hf_cfm_aps_bridge_type = -1; static int hf_cfm_raps_pdu = -1; static int hf_cfm_raps_req_st = -1; static int hf_cfm_raps_event_subcode = -1; static int hf_cfm_raps_subcode_reserved = -1; static int hf_cfm_raps_status = -1; static int hf_cfm_raps_status_rb = -1; static int hf_cfm_raps_status_dnf = -1; static int hf_cfm_raps_status_bpr = -1; static int hf_cfm_raps_status_reserved_v1 = -1; static int hf_cfm_raps_status_reserved_v2 = -1; static int hf_cfm_raps_node_id = -1; static int hf_cfm_raps_reserved = -1; static int hf_cfm_mcc_pdu = -1; static int hf_cfm_mcc_oui = -1; static int hf_cfm_mcc_subopcode = -1; static int hf_cfm_mcc_data = -1; static int hf_cfm_lmm_pdu = -1; static int hf_cfm_lmm_lmr_flags_Reserved = -1; static int hf_cfm_lmm_lmr_flags_Type = -1; static int hf_cfm_lmm_lmr_TxFCf = -1; static int hf_cfm_lmm_lmr_RxFCf = -1; static int hf_cfm_lmm_lmr_TxFCb = -1; static int hf_cfm_lmr_pdu = -1; static int hf_cfm_odm_pdu = -1; static int hf_cfm_odm_dmm_dmr_flags_Reserved = -1; static int hf_cfm_odm_dmm_dmr_flags_Type = -1; static int hf_cfm_odm_dmm_dmr_TxTimestampf = -1; static int hf_cfm_odm_dmm_dmr_RxTimestampf = -1; static int hf_cfm_dmm_pdu = -1; static int hf_cfm_dmm_dmr_TxTimestampb = -1; static int hf_cfm_dmm_dmr_RxTimestampb = -1; static int hf_cfm_dmr_pdu = -1; static int hf_cfm_exm_pdu = -1; static int hf_cfm_exm_oui = -1; static int hf_cfm_exm_subopcode = -1; static int hf_cfm_exm_data = -1; static int hf_cfm_exr_pdu = -1; static int hf_cfm_exr_oui = -1; static int hf_cfm_exr_subopcode = -1; static int hf_cfm_exr_data = -1; static int hf_cfm_vsm_pdu = -1; static int hf_cfm_vsm_oui = -1; static int hf_cfm_vsm_subopcode = -1; static int hf_cfm_vsm_data = -1; static int hf_cfm_vsr_pdu = -1; static int hf_cfm_vsr_oui = -1; static int hf_cfm_vsr_subopcode = -1; static int hf_cfm_vsr_data = -1; static int hf_cfm_csf_pdu = -1; static int hf_cfm_csf_flags_Reserved = -1; static int hf_cfm_csf_flags_Type = -1; static int hf_cfm_csf_flags_Period = -1; static int hf_cfm_osl_pdu = -1; static int hf_cfm_osl_src_mep = -1; static int hf_cfm_osl_reserved = -1; static int hf_cfm_osl_testid = -1; static int hf_cfm_osl_txfcf = -1; static int hf_cfm_slm_pdu = -1; static int hf_cfm_slm_slr_src_mep = -1; static int hf_cfm_slm_reserved = -1; static int hf_cfm_slm_slr_testid = -1; static int hf_cfm_slm_slr_txfcf = -1; static int hf_cfm_slr_pdu = -1; static int hf_cfm_slr_rsp_mep = -1; static int hf_cfm_slr_txfcb = -1; static int hf_cfm_unknown_pdu = -1; static int hf_cfm_unknown_flags = -1; static int hf_cfm_unknown_data = -1; static int hf_cfm_all_tlvs = -1; static int hf_cfm_tlv_type = -1; static int hf_cfm_tlv_length = -1; static int hf_tlv_chassis_id_length = -1; static int hf_tlv_chassis_id_subtype = -1; static int hf_tlv_chassis_id_chassis_component = -1; static int hf_tlv_chassis_id_interface_alias = -1; static int hf_tlv_chassis_id_port_component = -1; static int hf_tlv_chassis_id_mac_address = -1; static int hf_tlv_chassis_id_network_address_family = -1; static int hf_tlv_chassis_id_network_address_ipv4 = -1; static int hf_tlv_chassis_id_network_address_ipv6 = -1; static int hf_tlv_chassis_id_network_address_unknown = -1; static int hf_tlv_chassis_id_interface_name = -1; static int hf_tlv_chassis_id_locally_assigned = -1; static int hf_tlv_chassis_id_unknown = -1; static int hf_tlv_ma_domain_length = -1; static int hf_tlv_ma_domain = -1; static int hf_tlv_management_addr_length = -1; static int hf_tlv_management_addr_ipv4 = -1; static int hf_tlv_management_addr_ipv6 = -1; static int hf_tlv_management_addr_eth = -1; static int hf_tlv_management_addr_unknown = -1; static int hf_tlv_port_status_value = -1; static int hf_tlv_data_value = -1; static int hf_tlv_interface_status_value = -1; static int hf_tlv_reply_ingress_action = -1; static int hf_tlv_reply_ingress_mac_address = -1; static int hf_tlv_reply_ing_egr_portid_length = -1; static int hf_tlv_reply_ing_egr_portid_subtype = -1; static int hf_tlv_reply_ing_egr_portid_interface_alias = -1; static int hf_tlv_reply_ing_egr_portid_port_component = -1; static int hf_tlv_reply_ing_egr_portid_mac_address = -1; static int hf_tlv_reply_ing_egr_portid_network_address_family = -1; static int hf_tlv_reply_ing_egr_portid_network_address_ipv4 = -1; static int hf_tlv_reply_ing_egr_portid_network_address_ipv6 = -1; static int hf_tlv_reply_ing_egr_portid_network_address_unknown = -1; static int hf_tlv_reply_ing_egr_portid_interface_name = -1; static int hf_tlv_reply_ing_egr_portid_agent_circuit_id = -1; static int hf_tlv_reply_ing_egr_portid_locally_assigned = -1; static int hf_tlv_reply_ing_egr_portid_unknown = -1; static int hf_tlv_reply_egress_action = -1; static int hf_tlv_reply_egress_mac_address = -1; static int hf_tlv_ltr_egress_last_id_mac = -1; static int hf_tlv_ltr_egress_last_id_unique_identifier = -1; static int hf_tlv_ltr_egress_next_id_mac = -1; static int hf_tlv_ltr_egress_next_id_unique_identifier = -1; static int hf_tlv_ltm_egress_id_mac = -1; static int hf_tlv_ltm_egress_id_unique_identifier = -1; static int hf_tlv_pbb_te_mip_mac_address = -1; static int hf_tlv_pbb_te_reverse_vid = -1; static int hf_tlv_pbb_te_reverse_mac = -1; static int hf_tlv_org_spec_oui = -1; static int hf_tlv_org_spec_subtype = -1; static int hf_tlv_org_spec_value = -1; static int hf_tlv_tst_test_pattern_type = -1; static int hf_tlv_tst_test_pattern = -1; static int hf_tlv_tst_CRC32 = -1; static int hf_tlv_tgt_rpl_mep_mip_id_subtype = -1; static int hf_tlv_tgt_rpl_padding = -1; static int hf_tlv_tgt_rpl_mep_id = -1; static int hf_tlv_tgt_rpl_mip_id_icc = -1; static int hf_tlv_tgt_rpl_mip_id_node_id = -1; static int hf_tlv_tgt_rpl_mip_id_if_num = -1; static int hf_tlv_tgt_rpl_mip_id_cc = -1; static int hf_tlv_req_mep_id_lb = -1; static int hf_tlv_req_mep_id_reserved = -1; static int hf_tlv_tst_id_test_id = -1; static int hf_tlv_unknown_data = -1; static gint ett_cfm = -1; static gint ett_cfm_pdu = -1; static gint ett_cfm_flags = -1; static gint ett_cfm_maid = -1; static gint ett_cfm_ccm_itu = -1; static gint ett_cfm_all_tlvs = -1; static gint ett_cfm_tlv = -1; static gint ett_cfm_raps_status = -1; static expert_field ei_tlv_tst_id_length = EI_INIT; static expert_field ei_tlv_management_addr_length = EI_INIT; static dissector_handle_t cfm_handle; /* CFM EOAM sub-protocol dissectors */ static int dissect_mep_maid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_tree *cfm_maid_tree; gint maid_offset; guint32 maid_md_name_format; guint32 maid_ma_name_format; guint32 maid_ma_name_length; proto_tree_add_item(tree, hf_cfm_mep_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; ti = proto_tree_add_item(tree, hf_cfm_maid, tvb, offset, 48, ENC_NA); cfm_maid_tree = proto_item_add_subtree(ti, ett_cfm_maid); maid_offset = offset; proto_tree_add_item_ret_uint(cfm_maid_tree, hf_cfm_maid_md_name_format, tvb, maid_offset, 1, ENC_NA, &maid_md_name_format); maid_offset += 1; if (maid_md_name_format != MD_NAME_FMT_NONE) { // NOTE: true for IEEE 802.1Q CCM only guint8 maid_md_name_length; proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_md_name_length, tvb, maid_offset, 1, ENC_NA); maid_md_name_length = tvb_get_guint8(tvb, maid_offset); maid_offset += 1; if (maid_md_name_length) { // NOTE: Between 1 and 43 switch (maid_md_name_format) { case MD_NAME_FMT_MAC_ID: if (maid_md_name_length != 8) { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_md_name_hex, tvb, maid_offset, maid_md_name_length, ENC_NA); } else { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_md_name_mac, tvb, maid_offset, 6, ENC_NA); proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_md_name_mac_id, tvb, maid_offset + 6, 2, ENC_NA); } break; case MD_NAME_FMT_DOMAIN: case MD_NAME_FMT_STRING: proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_md_name_string, tvb, maid_offset, maid_md_name_length, ENC_ASCII|ENC_NA); break; default: proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_md_name_hex, tvb, maid_offset, maid_md_name_length, ENC_NA); break; } maid_offset += maid_md_name_length; } } proto_tree_add_item_ret_uint(cfm_maid_tree, hf_cfm_maid_ma_name_format, tvb, maid_offset, 1, ENC_NA, &maid_ma_name_format); maid_offset += 1; proto_tree_add_item_ret_uint(cfm_maid_tree, hf_cfm_maid_ma_name_length, tvb, maid_offset, 1, ENC_NA, &maid_ma_name_length); maid_offset += 1; switch (maid_ma_name_format) { case MA_NAME_FMT_RESVD: proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_hex, tvb, maid_offset, maid_ma_name_length, ENC_NA); break; case MA_NAME_FMT_PVID: if (maid_ma_name_length != 2) { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_hex, tvb, maid_offset, maid_ma_name_length, ENC_NA); } else { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_pvid, tvb, maid_offset, 2, ENC_NA); } break; case MA_NAME_FMT_STRING: proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_string, tvb, maid_offset, maid_ma_name_length, ENC_ASCII|ENC_NA); break; case MA_NAME_FMT_ID: if (maid_ma_name_length != 2) { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_hex, tvb, maid_offset, maid_ma_name_length, ENC_NA); } else { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_id, tvb, maid_offset, 2, ENC_NA); } break; case MA_NAME_FMT_VPN_ID: if (maid_ma_name_length != 7) { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_hex, tvb, maid_offset, maid_ma_name_length, ENC_NA); } else { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_vpnid_oui, tvb, maid_offset, 3, ENC_NA); proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_vpnid_index, tvb, maid_offset + 3, 4, ENC_NA); } break; case MA_NAME_FMT_ICC: if (maid_ma_name_length != 13) { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_hex, tvb, maid_offset, maid_ma_name_length, ENC_NA); } else { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_icc_umc, tvb, maid_offset, 13, ENC_ASCII|ENC_NA); } break; case MA_NAME_FMT_ICC_CC: if (maid_ma_name_length != 15) { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_hex, tvb, maid_offset, maid_ma_name_length, ENC_NA); } else { proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_cc, tvb, maid_offset, 2, ENC_ASCII|ENC_NA); proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_icc_umc, tvb, maid_offset + 2, 13, ENC_ASCII|ENC_NA); } break; default: proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_ma_name_hex, tvb, maid_offset, maid_ma_name_length, ENC_NA); break; } maid_offset += maid_ma_name_length; offset += 48; if (offset > maid_offset) { gint padding_length; padding_length = offset - maid_offset; proto_tree_add_item(cfm_maid_tree, hf_cfm_maid_padding, tvb, maid_offset, padding_length, ENC_NA); } return offset; } static int dissect_cfm_ccm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; proto_item *wi; proto_tree *cfm_ccm_itu_tree; ti = proto_tree_add_item(tree, hf_cfm_ccm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_ccm_flags_RDI, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_ccm_flags_Traffic, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_ccm_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_ccm_flags_Interval, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_ccm_seq_number, tvb, offset, 4, ENC_BIG_ENDIAN); // NOTE: Zero in Y.1731 offset += 4; /* dissect CCM MEP ID + MAID */ offset = dissect_mep_maid(tvb, pinfo, cfm_pdu_tree, offset); /* Dissect 16 octets reserved for Y.1731, samples of the wrap-around frame counters */ wi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_ccm_itu_t_y1731, tvb, offset, 16, ENC_NA); cfm_ccm_itu_tree = proto_item_add_subtree(wi, ett_cfm_ccm_itu); proto_tree_add_item(cfm_ccm_itu_tree, hf_cfm_ccm_itu_TxFCf, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_ccm_itu_tree, hf_cfm_ccm_itu_RxFCb, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_ccm_itu_tree, hf_cfm_ccm_itu_TxFCb, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_ccm_itu_tree, hf_cfm_ccm_itu_reserved, tvb, offset, 4, ENC_NA); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_lbm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_lbm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_lbm_lbr_transaction_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_lbr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_lbr_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_lbm_lbr_transaction_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_ltm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_ltm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_ltm_flags_UseFDBonly, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_ltm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_ltm_ltr_transaction_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_ltm_ltr_ttl, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_ltm_orig_addr, tvb, offset, 6, ENC_NA); offset += 6; proto_tree_add_item(cfm_pdu_tree, hf_cfm_ltm_targ_addr, tvb, offset, 6, ENC_NA); offset += 6; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_ltr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_ltr_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_ltr_flags_UseFDBonly, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_ltr_flags_FwdYes, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_ltr_flags_TerminalMEP, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_ltr_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_ltm_ltr_transaction_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_ltm_ltr_ttl, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_ltr_relay_action, tvb, offset, 1, ENC_NA); offset += 1; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_rfm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_rfm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_rfm_transaction_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_sfm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_sfm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_sfm_transaction_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_bnm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_bnm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_bnm_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_bnm_flags_Period, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_gnm_subopcode, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_bnm_nominal_bw, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_bnm_current_bw, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_bnm_port_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_gnm_unknown(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_gnm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_gnm_unknown_flags, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_gnm_subopcode, tvb, offset, 1, ENC_NA); offset += 1; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_gnm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset) { guint8 cfm_gnm_pdu_type = tvb_get_guint8(tvb, offset + 4); switch (cfm_gnm_pdu_type) { case BNM: offset = dissect_cfm_bnm(tvb, pinfo, tree, offset); break; default: offset = dissect_cfm_gnm_unknown(tvb, pinfo, tree, offset); break; } return offset; } static int dissect_cfm_ais(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_ais_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_ais_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_ais_flags_Period, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_lck(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_lck_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_lck_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_lck_flags_Period, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_tst(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_tst_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_tst_sequence_num, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_aps(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_aps_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_aps_req_st, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_pdu_tree, hf_cfm_aps_protection_type_A, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_pdu_tree, hf_cfm_aps_protection_type_B, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_pdu_tree, hf_cfm_aps_protection_type_D, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_pdu_tree, hf_cfm_aps_protection_type_R, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_aps_requested_signal, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_aps_bridged_signal, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_aps_bridge_type, tvb, offset, 1, ENC_NA); offset += 1; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_raps(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; guint version; guint32 raps_requeststate; proto_item *ri; proto_tree *raps_status_tree; ti = proto_tree_add_item(tree, hf_cfm_raps_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_raps_req_st, tvb, offset, 1, ENC_NA, &raps_requeststate); version = (tvb_get_guint8(tvb, CFM_LEVEL_VERSION_OFFSET) & CFM_VERSION_MASK) >> CFM_VERSION_SHIFT; if (version == 1 && raps_requeststate == RAPS_REQ_ST_EVENT) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_raps_event_subcode, tvb, offset, 1, ENC_NA); } else { proto_tree_add_item(cfm_pdu_tree, hf_cfm_raps_subcode_reserved, tvb, offset, 1, ENC_NA); } offset += 1; ri = proto_tree_add_item(cfm_pdu_tree, hf_cfm_raps_status, tvb, offset, 1, ENC_NA); raps_status_tree = proto_item_add_subtree(ri, ett_cfm_raps_status); proto_tree_add_item(raps_status_tree, hf_cfm_raps_status_rb, tvb, offset, 1, ENC_NA); proto_tree_add_item(raps_status_tree, hf_cfm_raps_status_dnf, tvb, offset, 1, ENC_NA); /* R-APS(G.8032) v2 only */ if (version == 1) { proto_tree_add_item(raps_status_tree, hf_cfm_raps_status_bpr, tvb, offset, 1, ENC_NA); proto_tree_add_item(raps_status_tree, hf_cfm_raps_status_reserved_v2, tvb, offset, 1, ENC_NA); } else { proto_tree_add_item(raps_status_tree, hf_cfm_raps_status_reserved_v1, tvb, offset, 1, ENC_NA); } offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_raps_node_id, tvb, offset, 6, ENC_NA); offset += 6; proto_tree_add_item(cfm_pdu_tree, hf_cfm_raps_reserved, tvb, offset, 24, ENC_NA); offset += 24; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int find_end_tlv(tvbuff_t *tvb, gint first_tlv_offset) { /* * XXX - how to handle TLVs in MCC, EXM, EXR, VSM or VSR PDU data? * The TLV Offset points to the first TLV, which may part of PDU Data, therefore defined * 'outside the scope of this standard'. Therefore these cannot be simply handed off the * standard TLV dissection functions. We do however want to find the End TLV. * All we can do is iterate over these unknown TLVs, under the assumption they use the * same format as defined in this standard, until we find the End TLV. * Don't break dissection if we can't find it this way, e.g. when the captured frame is * cut short. Then assume all remaining captured frame data is PDU data. */ gint tlv_tvb_offset = CFM_COMMON_HEADER_LEN + first_tlv_offset; for (;;) { // Does a tag exist in the captured data? if (tvb_bytes_exist(tvb, tlv_tvb_offset, 1)) { // Is this the End TLV if (tvb_get_guint8(tvb, tlv_tvb_offset)) { // Following the tag, does the length exist in the captured data? if (tvb_captured_length_remaining(tvb, tlv_tvb_offset) < 3) { tlv_tvb_offset = 0; break; } // Go to the next tag tlv_tvb_offset += tvb_get_ntohs(tvb, tlv_tvb_offset + 1) + 3; } else { break; // we found the END_TLV } } else { tlv_tvb_offset = 0; break; } } return tlv_tvb_offset; } static int dissect_cfm_mcc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint tlv_tvb_offset; ti = proto_tree_add_item(tree, hf_cfm_mcc_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; /* XXX - Introducing a dissector table would allow to register subdissectors based on * their subopcode, per OUI. The OUI table creation would be similar to the registration * function in the IEEE 802a dissector. */ proto_tree_add_item(cfm_pdu_tree, hf_cfm_mcc_oui, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; proto_tree_add_item(cfm_pdu_tree, hf_cfm_mcc_subopcode, tvb, offset, 1, ENC_NA); offset += 1; tlv_tvb_offset = find_end_tlv(tvb, first_tlv_offset); proto_tree_add_item(cfm_pdu_tree, hf_cfm_mcc_data, tvb, offset, (tlv_tvb_offset) ? (tlv_tvb_offset - offset) : -1, ENC_NA); offset = (tlv_tvb_offset) ? tlv_tvb_offset : (gint)tvb_captured_length(tvb); proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_lmm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_lmm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_lmm_lmr_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_lmm_lmr_flags_Type, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_lmm_lmr_TxFCf, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_lmm_lmr_RxFCf, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_lmm_lmr_TxFCb, tvb, offset, 4, ENC_NA); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_lmr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_lmr_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_lmm_lmr_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_lmm_lmr_flags_Type, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_lmm_lmr_TxFCf, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_lmm_lmr_RxFCf, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_lmm_lmr_TxFCb, tvb, offset, 4, ENC_NA); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_odm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_odm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_odm_dmm_dmr_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_odm_dmm_dmr_flags_Type, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_odm_dmm_dmr_TxTimestampf, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(cfm_pdu_tree, hf_cfm_odm_dmm_dmr_RxTimestampf, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_dmm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_dmm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_odm_dmm_dmr_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_odm_dmm_dmr_flags_Type, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_odm_dmm_dmr_TxTimestampf, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(cfm_pdu_tree, hf_cfm_odm_dmm_dmr_RxTimestampf, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(cfm_pdu_tree, hf_cfm_dmm_dmr_TxTimestampb, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(cfm_pdu_tree, hf_cfm_dmm_dmr_RxTimestampb, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_dmr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_dmr_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_odm_dmm_dmr_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_odm_dmm_dmr_flags_Type, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_odm_dmm_dmr_TxTimestampf, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(cfm_pdu_tree, hf_cfm_odm_dmm_dmr_RxTimestampf, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(cfm_pdu_tree, hf_cfm_dmm_dmr_TxTimestampb, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(cfm_pdu_tree, hf_cfm_dmm_dmr_RxTimestampb, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); offset += 8; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_exm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint tlv_tvb_offset; ti = proto_tree_add_item(tree, hf_cfm_exm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; /* XXX - Introducing a dissector table would allow to register subdissectors based on * their subopcode, per OUI. The OUI table creation would be similar to the registration * function in the IEEE 802a dissector. */ proto_tree_add_item(cfm_pdu_tree, hf_cfm_exm_oui, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; proto_tree_add_item(cfm_pdu_tree, hf_cfm_exm_subopcode, tvb, offset, 1, ENC_NA); offset += 1; tlv_tvb_offset = find_end_tlv(tvb, first_tlv_offset); proto_tree_add_item(cfm_pdu_tree, hf_cfm_exm_data, tvb, offset, (tlv_tvb_offset) ? (tlv_tvb_offset - offset) : -1, ENC_NA); offset = (tlv_tvb_offset) ? tlv_tvb_offset : (gint)tvb_captured_length(tvb); proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_exr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint tlv_tvb_offset; ti = proto_tree_add_item(tree, hf_cfm_exr_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; /* XXX - Introducing a dissector table would allow to register subdissectors based on * their subopcode, per OUI. The OUI table creation would be similar to the registration * function in the IEEE 802a dissector. */ proto_tree_add_item(cfm_pdu_tree, hf_cfm_exr_oui, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; proto_tree_add_item(cfm_pdu_tree, hf_cfm_exr_subopcode, tvb, offset, 1, ENC_NA); offset += 1; tlv_tvb_offset = find_end_tlv(tvb, first_tlv_offset); proto_tree_add_item(cfm_pdu_tree, hf_cfm_exr_data, tvb, offset, (tlv_tvb_offset) ? (tlv_tvb_offset - offset) : -1, ENC_NA); offset = (tlv_tvb_offset) ? tlv_tvb_offset : (gint)tvb_captured_length(tvb); proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_vsm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint tlv_tvb_offset; ti = proto_tree_add_item(tree, hf_cfm_vsm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; /* XXX - Introducing a dissector table would allow to register subdissectors based on * their subopcode, per OUI. The OUI table creation would be similar to the registration * function in the IEEE 802a dissector. */ proto_tree_add_item(cfm_pdu_tree, hf_cfm_vsm_oui, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; proto_tree_add_item(cfm_pdu_tree, hf_cfm_vsm_subopcode, tvb, offset, 1, ENC_NA); offset += 1; tlv_tvb_offset = find_end_tlv(tvb, first_tlv_offset); proto_tree_add_item(cfm_pdu_tree, hf_cfm_vsm_data, tvb, offset, (tlv_tvb_offset) ? (tlv_tvb_offset - offset) : -1, ENC_NA); offset = (tlv_tvb_offset) ? tlv_tvb_offset : (gint)tvb_captured_length(tvb); proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_vsr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint tlv_tvb_offset; ti = proto_tree_add_item(tree, hf_cfm_vsr_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; /* XXX - Introducing a dissector table would allow to register subdissectors based on * their subopcode, per OUI. The OUI table creation would be similar to the registration * function in the IEEE 802a dissector. */ proto_tree_add_item(cfm_pdu_tree, hf_cfm_vsr_oui, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; proto_tree_add_item(cfm_pdu_tree, hf_cfm_vsr_subopcode, tvb, offset, 1, ENC_NA); offset += 1; tlv_tvb_offset = find_end_tlv(tvb, first_tlv_offset); proto_tree_add_item(cfm_pdu_tree, hf_cfm_vsr_data, tvb, offset, (tlv_tvb_offset) ? (tlv_tvb_offset - offset) : -1, ENC_NA); offset = (tlv_tvb_offset) ? tlv_tvb_offset : (gint)tvb_captured_length(tvb); proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_csf(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_csf_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_csf_flags_Reserved, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_csf_flags_Type, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_flag_tree, hf_cfm_csf_flags_Period, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_osl(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_osl_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_osl_src_mep, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(cfm_pdu_tree, hf_cfm_osl_reserved, tvb, offset, 2, ENC_NA); offset += 2; proto_tree_add_item(cfm_pdu_tree, hf_cfm_osl_testid, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_osl_txfcf, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_osl_reserved, tvb, offset, 4, ENC_NA); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_slm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_slm_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slm_slr_src_mep, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slm_reserved, tvb, offset, 2, ENC_NA); offset += 2; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slm_slr_testid, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slm_slr_txfcf, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slm_reserved, tvb, offset, 4, ENC_NA); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_slr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_slr_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_flags_Reserved, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slm_slr_src_mep, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slr_rsp_mep, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slm_slr_testid, tvb, offset, 4, ENC_NA); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slm_slr_txfcf, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(cfm_pdu_tree, hf_cfm_slr_txfcb, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } static int dissect_cfm_unknown(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset) { proto_item *ti; proto_item *fi; proto_tree *cfm_pdu_tree; proto_tree *cfm_flag_tree; guint32 first_tlv_offset; gint start_offset = offset; gint length_remaining; ti = proto_tree_add_item(tree, hf_cfm_unknown_pdu, tvb, offset, -1, ENC_NA); cfm_pdu_tree = proto_item_add_subtree(ti, ett_cfm_pdu); fi = proto_tree_add_item(cfm_pdu_tree, hf_cfm_flags, tvb, offset, 1, ENC_NA); cfm_flag_tree = proto_item_add_subtree(fi, ett_cfm_flags); proto_tree_add_item(cfm_flag_tree, hf_cfm_unknown_flags, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item_ret_uint(cfm_pdu_tree, hf_cfm_first_tlv_offset, tvb, offset, 1, ENC_NA, &first_tlv_offset); offset += 1; length_remaining = first_tlv_offset - (offset - (start_offset + 2)); if (length_remaining > 0) { proto_tree_add_item(cfm_pdu_tree, hf_cfm_unknown_data, tvb, offset, length_remaining, ENC_NA); offset += length_remaining; } proto_item_set_len(ti, offset - start_offset); return offset; } /* Inspired by packet-lldp.c:dissect_lldp_chassis_id() */ static int sender_id_tlv_chassis_id(proto_tree *cfm_tlv_tree, tvbuff_t *tvb, gint tlv_data_offset, guint8 tlv_chassis_id_length) { proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_subtype, tvb, tlv_data_offset, 1, ENC_NA); guint8 chassis_id_subtype = tvb_get_guint8(tvb, tlv_data_offset); tlv_data_offset += 1; tlv_chassis_id_length -= 1; switch (chassis_id_subtype) { case 1: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_chassis_component, tvb, tlv_data_offset, tlv_chassis_id_length, ENC_UTF_8); break; case 2: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_interface_alias, tvb, tlv_data_offset, tlv_chassis_id_length, ENC_UTF_8); break; case 3: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_port_component, tvb, tlv_data_offset, tlv_chassis_id_length, ENC_NA); break; case 4: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_mac_address, tvb, tlv_data_offset, tlv_chassis_id_length, ENC_NA); break; case 5: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_network_address_family, tvb, tlv_data_offset, 1, ENC_NA); switch (tvb_get_guint8(tvb, tlv_data_offset)) { case AFNUM_INET: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_network_address_ipv4, tvb, tlv_data_offset+1, tlv_chassis_id_length-1, ENC_BIG_ENDIAN); break; case AFNUM_INET6: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_network_address_ipv6, tvb, tlv_data_offset+1, tlv_chassis_id_length-1, ENC_NA); break; default: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_network_address_unknown, tvb, tlv_data_offset+1, tlv_chassis_id_length-1, ENC_NA); break; } break; case 6: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_interface_name, tvb, tlv_data_offset, tlv_chassis_id_length, ENC_UTF_8); break; case 7: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_locally_assigned, tvb, tlv_data_offset, tlv_chassis_id_length, ENC_UTF_8); break; default: proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_unknown, tvb, tlv_data_offset, tlv_chassis_id_length, ENC_NA); break; } tlv_data_offset += tlv_chassis_id_length; return tlv_data_offset; } static int sender_id_tlv_management_address(proto_tree *cfm_tlv_tree, tvbuff_t *tvb, void *tlv_ma_domain_oid, guint8 tlv_ma_domain_length, gint tlv_data_offset, guint8 tlv_management_addr_length) { struct { const guint8 *oid; // BER encoded const size_t oid_length; const int *header_field; const int encoding; } management_address_type[] = { // transportDomainUdpIpv4 : 1.3.6.1.2.1.100.1.1 { (const guint8[]){ 0x2B, 0x06, 0x01, 0x02, 0x01, 0x64, 0x01, 0x01 }, 8, &hf_tlv_management_addr_ipv4, ENC_BIG_ENDIAN }, // transportDomainUdpIpv6 : 1.3.6.1.2.1.100.1.2 { (const guint8[]){ 0x2B, 0x06, 0x01, 0x02, 0x01, 0x64, 0x01, 0x02 }, 8, &hf_tlv_management_addr_ipv6, ENC_NA }, // transportDomainTcpIpv4 : 1.3.6.1.2.1.100.1.5 { (const guint8[]){ 0x2B, 0x06, 0x01, 0x02, 0x01, 0x64, 0x01, 0x05 }, 8, &hf_tlv_management_addr_ipv4, ENC_BIG_ENDIAN }, // transportDomainTcpIpv6 : 1.3.6.1.2.1.100.1.6 { (const guint8[]){ 0x2B, 0x06, 0x01, 0x02, 0x01, 0x64, 0x01, 0x06 }, 8, &hf_tlv_management_addr_ipv6, ENC_NA }, // transportDomainSctpIpv4 : 1.3.6.1.2.1.100.1.9 { (const guint8[]){ 0x2B, 0x06, 0x01, 0x02, 0x01, 0x64, 0x01, 0x09 }, 8, &hf_tlv_management_addr_ipv4, ENC_BIG_ENDIAN }, // transportDomainSctpIpv6 : 1.3.6.1.2.1.100.1.10 { (const guint8[]){ 0x2B, 0x06, 0x01, 0x02, 0x01, 0x64, 0x01, 0x0A }, 8, &hf_tlv_management_addr_ipv6, ENC_NA }, // snmpIeee802Domain : 1.3.6.1.6.1.6 { (const guint8[]){ 0x2B, 0x06, 0x01, 0x06, 0x01, 0x06 }, 6, &hf_tlv_management_addr_eth, ENC_NA }, // End tag { NULL, 0, NULL, ENC_NA } }; for (size_t i = 0; i < array_length(management_address_type); i++) { if (management_address_type[i].oid == NULL) { proto_tree_add_item(cfm_tlv_tree, hf_tlv_management_addr_unknown, tvb, tlv_data_offset, tlv_management_addr_length, ENC_NA); break; } if (tlv_ma_domain_length == management_address_type[i].oid_length) { if (!(memcmp(tlv_ma_domain_oid, management_address_type[i].oid, tlv_ma_domain_length))) { proto_tree_add_item(cfm_tlv_tree, *management_address_type[i].header_field, tvb, tlv_data_offset, tlv_management_addr_length, management_address_type[i].encoding); break; } } } tlv_data_offset += tlv_management_addr_length; return tlv_data_offset; } /* Inspired by packet-lldp.c:dissect_lldp_port_id() */ static int reply_ing_egr_tlv_port_id(proto_tree *cfm_tlv_tree, tvbuff_t *tvb, gint tlv_data_offset, guint8 tlv_reply_ingress_portid_length) { proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_subtype, tvb, tlv_data_offset, 1, ENC_NA); guint8 port_id_subtype = tvb_get_guint8(tvb, tlv_data_offset); tlv_data_offset += 1; tlv_reply_ingress_portid_length -= 1; switch (port_id_subtype) { case 1: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_interface_alias, tvb, tlv_data_offset, tlv_reply_ingress_portid_length, ENC_UTF_8); break; case 2: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_port_component, tvb, tlv_data_offset, tlv_reply_ingress_portid_length, ENC_NA); break; case 3: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_mac_address, tvb, tlv_data_offset, tlv_reply_ingress_portid_length, ENC_NA); break; case 4: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_network_address_family, tvb, tlv_data_offset, 1, ENC_NA); switch (tvb_get_guint8(tvb, tlv_data_offset)) { case AFNUM_INET: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_network_address_ipv4, tvb, tlv_data_offset+1, tlv_reply_ingress_portid_length-1, ENC_BIG_ENDIAN); break; case AFNUM_INET6: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_network_address_ipv6, tvb, tlv_data_offset+1, tlv_reply_ingress_portid_length-1, ENC_NA); break; default: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_network_address_unknown, tvb, tlv_data_offset+1, tlv_reply_ingress_portid_length-1, ENC_NA); break; } break; case 5: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_interface_name, tvb, tlv_data_offset, tlv_reply_ingress_portid_length, ENC_UTF_8); break; case 6: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_agent_circuit_id, tvb, tlv_data_offset, tlv_reply_ingress_portid_length, ENC_NA); break; case 7: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_locally_assigned, tvb, tlv_data_offset, tlv_reply_ingress_portid_length, ENC_UTF_8); break; default: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_unknown, tvb, tlv_data_offset, tlv_reply_ingress_portid_length, ENC_NA); break; } tlv_data_offset += tlv_reply_ingress_portid_length; return tlv_data_offset; } /* Main CFM EOAM protocol dissector */ static int dissect_cfm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { gint offset = 0; guint8 cfm_pdu_type; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFM"); col_clear(pinfo->cinfo, COL_INFO); cfm_pdu_type = tvb_get_guint8(tvb, CFM_OPCODE_OFFSET); col_add_fstr(pinfo->cinfo, COL_INFO, "Type %s", val_to_str(cfm_pdu_type, opcode_type_name_vals, "Unknown (0x%02x)")); proto_item *ti; proto_tree *cfm_tree; /* isolate the payload of the packet */ ti = proto_tree_add_item(tree, proto_cfm, tvb, 0, -1, ENC_NA); /* report type of CFM packet to base of dissection tree */ proto_item_append_text(ti, ", Type %s", val_to_str(cfm_pdu_type, opcode_type_name_vals, "Unknown (0x%02x)")); /* dissecting the common CFM header */ cfm_tree = proto_item_add_subtree(ti, ett_cfm); proto_tree_add_item(cfm_tree, hf_cfm_md_level, tvb, offset, 1, ENC_NA); proto_tree_add_item(cfm_tree, hf_cfm_version, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(cfm_tree, hf_cfm_opcode, tvb, offset, 1, ENC_NA); offset += 1; switch (cfm_pdu_type) { case CCM: offset = dissect_cfm_ccm(tvb, pinfo, cfm_tree, offset); break; case LBM: offset = dissect_cfm_lbm(tvb, pinfo, cfm_tree, offset); break; case LBR: offset = dissect_cfm_lbr(tvb, pinfo, cfm_tree, offset); break; case LTM: offset = dissect_cfm_ltm(tvb, pinfo, cfm_tree, offset); break; case LTR: offset = dissect_cfm_ltr(tvb, pinfo, cfm_tree, offset); break; case RFM: offset = dissect_cfm_rfm(tvb, pinfo, cfm_tree, offset); break; case SFM: offset = dissect_cfm_sfm(tvb, pinfo, cfm_tree, offset); break; case GNM: offset = dissect_cfm_gnm(tvb, pinfo, cfm_tree, offset); break; case AIS: offset = dissect_cfm_ais(tvb, pinfo, cfm_tree, offset); break; case LCK: offset = dissect_cfm_lck(tvb, pinfo, cfm_tree, offset); break; case TST: offset = dissect_cfm_tst(tvb, pinfo, cfm_tree, offset); break; case APS: offset = dissect_cfm_aps(tvb, pinfo, cfm_tree, offset); break; case RAPS: offset = dissect_cfm_raps(tvb, pinfo, cfm_tree, offset); break; case MCC: offset = dissect_cfm_mcc(tvb, pinfo, cfm_tree, offset); break; case LMM: offset = dissect_cfm_lmm(tvb, pinfo, cfm_tree, offset); break; case LMR: offset = dissect_cfm_lmr(tvb, pinfo, cfm_tree, offset); break; case ODM: offset = dissect_cfm_odm(tvb, pinfo, cfm_tree, offset); break; case DMM: offset = dissect_cfm_dmm(tvb, pinfo, cfm_tree, offset); break; case DMR: offset = dissect_cfm_dmr(tvb, pinfo, cfm_tree, offset); break; case EXM: offset = dissect_cfm_exm(tvb, pinfo, cfm_tree, offset); break; case EXR: offset = dissect_cfm_exr(tvb, pinfo, cfm_tree, offset); break; case VSM: offset = dissect_cfm_vsm(tvb, pinfo, cfm_tree, offset); break; case VSR: offset = dissect_cfm_vsr(tvb, pinfo, cfm_tree, offset); break; case CSF: offset = dissect_cfm_csf(tvb, pinfo, cfm_tree, offset); break; case OSL: offset = dissect_cfm_osl(tvb, pinfo, cfm_tree, offset); break; case SLM: offset = dissect_cfm_slm(tvb, pinfo, cfm_tree, offset); break; case SLR: offset = dissect_cfm_slr(tvb, pinfo, cfm_tree, offset); break; default: offset = dissect_cfm_unknown(tvb, pinfo, cfm_tree, offset); break; } /* Get the First TLV offset and add the offset of the common CFM header*/ gint cfm_first_tlv_offset = tvb_get_guint8(tvb, CFM_1ST_TLV_OFFSET) + CFM_COMMON_HEADER_LEN; /* The TLV offset should be the same as where the PDU left off or we have a problem */ if (cfm_first_tlv_offset != offset) { // TODO: Report error, recover and continue cfm_first_tlv_offset = offset; } /* Begin dissecting the TLV's */ proto_item *cfm_all_tlvs_ti; proto_tree *cfm_all_tlvs_tree; cfm_all_tlvs_ti = proto_tree_add_item(cfm_tree, hf_cfm_all_tlvs, tvb, cfm_first_tlv_offset, -1, ENC_NA); cfm_all_tlvs_tree = proto_item_add_subtree(cfm_all_tlvs_ti, ett_cfm_all_tlvs); gint cfm_tlv_offset = cfm_first_tlv_offset; do { guint8 cfm_tlv_type; guint16 cfm_tlv_length; proto_tree *cfm_tlv_tree; proto_item *cfm_tlv_ti, *expert_ti; gint tlv_data_offset; gboolean test_id_length_bogus = FALSE; cfm_tlv_type = tvb_get_guint8(tvb, cfm_tlv_offset); if (cfm_tlv_type == END_TLV) { cfm_tlv_tree = proto_tree_add_subtree_format(cfm_all_tlvs_tree, tvb, cfm_tlv_offset, 1, ett_cfm_tlv, NULL, "TLV: End TLV (t=0,l=0)"); proto_tree_add_item(cfm_tlv_tree, hf_cfm_tlv_type, tvb, cfm_tlv_offset, 1, ENC_NA); cfm_tlv_offset += 1; break; } cfm_tlv_length = tvb_get_ntohs(tvb, cfm_tlv_offset+1); if (cfm_tlv_type == TEST_ID_TLV && cfm_tlv_length == 32) { /* ITU-T G.8013/Y.1731 9.14.2 indicates that the * Length of the Test ID TLV "must be 32" (indicating * the bit length?) even though the Value is 4 octets, * contradicting IEEE 802.1Q 21.5 TLV format: * "The 16 bits of the Length field indicate the size, * in octets, of the Value field." */ cfm_tlv_length = 4; test_id_length_bogus = TRUE; } cfm_tlv_tree = proto_tree_add_subtree_format(cfm_all_tlvs_tree, tvb, cfm_tlv_offset, cfm_tlv_length+3, ett_cfm_tlv, NULL, "TLV: %s (t=%d,l=%d)", val_to_str(cfm_tlv_type, tlv_type_field_vals, "Unknown (0x%02x)"), cfm_tlv_type, cfm_tlv_length); proto_tree_add_item(cfm_tlv_tree, hf_cfm_tlv_type, tvb, cfm_tlv_offset, 1, ENC_NA); cfm_tlv_offset += 1; cfm_tlv_ti = proto_tree_add_item(cfm_tlv_tree, hf_cfm_tlv_length, tvb, cfm_tlv_offset, 2, ENC_BIG_ENDIAN); if (test_id_length_bogus) { expert_add_info(pinfo, cfm_tlv_ti, &ei_tlv_tst_id_length); } cfm_tlv_offset += 2; if (cfm_tlv_length == 0) continue; tlv_data_offset = cfm_tlv_offset; switch(cfm_tlv_type) { case SENDER_ID_TLV: { guint8 tlv_chassis_id_length; proto_tree_add_item(cfm_tlv_tree, hf_tlv_chassis_id_length, tvb, tlv_data_offset, 1, ENC_NA); tlv_chassis_id_length = tvb_get_guint8(tvb,tlv_data_offset); tlv_data_offset += 1; if (tlv_chassis_id_length > 0) { tlv_data_offset = sender_id_tlv_chassis_id(cfm_tlv_tree, tvb, tlv_data_offset, tlv_chassis_id_length); } /* IEEE 802.1Q 21.5.3.2 If the Chassis ID Length field * is 0, then the Chassis ID Subtype is not present. */ uint16_t chassis_id_tot_length = tlv_chassis_id_length ? 2 + tlv_chassis_id_length : 1; /* If the TLV length is greater than the number of octets used for the * Chassis ID, then we must have a Management Address Domain */ if (cfm_tlv_length > chassis_id_tot_length) { guint8 tlv_ma_domain_length; void *tlv_ma_domain_oid = NULL; proto_tree_add_item(cfm_tlv_tree, hf_tlv_ma_domain_length, tvb, tlv_data_offset, 1, ENC_NA); tlv_ma_domain_length = tvb_get_guint8(tvb, tlv_data_offset); tlv_data_offset += 1; if (tlv_ma_domain_length > 0) { // Ref ITU-T X690-2002 for OID. RFC 2579 for TDomain. proto_tree_add_item(cfm_tlv_tree, hf_tlv_ma_domain, tvb, tlv_data_offset, tlv_ma_domain_length, ENC_NA); tlv_ma_domain_oid = tvb_memdup(pinfo->pool, tvb, tlv_data_offset, tlv_ma_domain_length); tlv_data_offset += tlv_ma_domain_length; } /* If the TLV length is greater than the number of octets used for the * Chassis ID and the Management Address Domain, then we must have a * Management Address */ if (cfm_tlv_length > (chassis_id_tot_length + 1 + tlv_ma_domain_length)) { guint8 tlv_management_addr_length; expert_ti = proto_tree_add_item(cfm_tlv_tree, hf_tlv_management_addr_length, tvb, tlv_data_offset, 1, ENC_NA); /* IEEE 802.1Q 21.5.3.6 "[Management Address Length] is not * present if the Management Address Domain Length is not * present or contains a 0." */ if (tlv_ma_domain_length == 0) { expert_add_info(pinfo, expert_ti, &ei_tlv_management_addr_length); } tlv_management_addr_length = tvb_get_guint8(tvb, tlv_data_offset); tlv_data_offset += 1; if (tlv_management_addr_length > 0) { tlv_data_offset = sender_id_tlv_management_address(cfm_tlv_tree, tvb, tlv_ma_domain_oid, tlv_ma_domain_length, tlv_data_offset, tlv_management_addr_length); } } } break; } case PORT_STAT_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_port_status_value, tvb, tlv_data_offset, 1, ENC_NA); tlv_data_offset += 1; break; case DATA_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_data_value, tvb, tlv_data_offset, cfm_tlv_length, ENC_NA); tlv_data_offset += cfm_tlv_length; break; case INTERF_STAT_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_interface_status_value, tvb, tlv_data_offset, 1, ENC_NA); tlv_data_offset += 1; break; case REPLY_ING_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ingress_action, tvb, tlv_data_offset, 1, ENC_NA); tlv_data_offset += 1; proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ingress_mac_address, tvb, tlv_data_offset, 6, ENC_NA); tlv_data_offset += 6; /* For the IEEE standard if the TLV length is greater than 7 then we have an ingress port ID */ if (cfm_tlv_length > 7) { guint8 tlv_reply_ingress_portid_length; proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_length, tvb, tlv_data_offset, 1, ENC_NA); tlv_reply_ingress_portid_length = tvb_get_guint8(tvb,tlv_data_offset); tlv_data_offset += 1; if (tlv_reply_ingress_portid_length > 0) { tlv_data_offset = reply_ing_egr_tlv_port_id(cfm_tlv_tree, tvb, tlv_data_offset, tlv_reply_ingress_portid_length); } else { // TODO: Report error, cannot be zero. } } break; case REPLY_EGR_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_egress_action, tvb, tlv_data_offset, 1, ENC_NA); tlv_data_offset += 1; proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_egress_mac_address, tvb, tlv_data_offset, 6, ENC_NA); tlv_data_offset += 6; /* For the IEEE standard if the TLV length is greater than 7 then we have an egress port ID */ if (cfm_tlv_length > 7) { guint8 tlv_reply_egress_portid_length; proto_tree_add_item(cfm_tlv_tree, hf_tlv_reply_ing_egr_portid_length, tvb, tlv_data_offset, 1, ENC_NA); tlv_reply_egress_portid_length = tvb_get_guint8(tvb,tlv_data_offset); tlv_data_offset += 1; if (tlv_reply_egress_portid_length > 0) { tlv_data_offset = reply_ing_egr_tlv_port_id(cfm_tlv_tree, tvb, tlv_data_offset, tlv_reply_egress_portid_length); } else { // TODO: Report error, cannot be zero. } } break; case LTM_EGR_ID_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_ltm_egress_id_unique_identifier, tvb, tlv_data_offset, 2, ENC_NA); tlv_data_offset += 2; proto_tree_add_item(cfm_tlv_tree, hf_tlv_ltm_egress_id_mac, tvb, tlv_data_offset, 6, ENC_NA); tlv_data_offset += 6; break; case LTR_EGR_ID_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_ltr_egress_last_id_unique_identifier, tvb, tlv_data_offset, 2, ENC_NA); tlv_data_offset += 2; proto_tree_add_item(cfm_tlv_tree, hf_tlv_ltr_egress_last_id_mac, tvb, tlv_data_offset, 6, ENC_NA); tlv_data_offset += 6; proto_tree_add_item(cfm_tlv_tree, hf_tlv_ltr_egress_next_id_unique_identifier, tvb, tlv_data_offset, 2, ENC_NA); tlv_data_offset += 2; proto_tree_add_item(cfm_tlv_tree, hf_tlv_ltr_egress_next_id_mac, tvb, tlv_data_offset, 6, ENC_NA); tlv_data_offset += 6; break; case PPB_TE_MIP_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_pbb_te_mip_mac_address, tvb, tlv_data_offset, 6, ENC_NA); tlv_data_offset += 6; proto_tree_add_item(cfm_tlv_tree, hf_tlv_pbb_te_reverse_vid, tvb, tlv_data_offset, 2, ENC_BIG_ENDIAN); tlv_data_offset += 2; proto_tree_add_item(cfm_tlv_tree, hf_tlv_pbb_te_reverse_mac, tvb, tlv_data_offset, 6, ENC_NA); tlv_data_offset += 6; break; case DATA_PART1_TLV: case TRUNC_DATA_TLV: // TODO: hand off to ethertype dissector proto_tree_add_item(cfm_tlv_tree, hf_tlv_data_value, tvb, tlv_data_offset, cfm_tlv_length, ENC_NA); tlv_data_offset += cfm_tlv_length; break; case DATA_PART2_TLV: // NOTE: Appended to DATA_PART1_TLV this makes a complete Ethernet frame proto_tree_add_item(cfm_tlv_tree, hf_tlv_data_value, tvb, tlv_data_offset, cfm_tlv_length, ENC_NA); tlv_data_offset += cfm_tlv_length; break; case ORG_SPEC_TLV: if (cfm_tlv_length > 3) { proto_tree_add_item(cfm_tlv_tree, hf_tlv_org_spec_oui, tvb, tlv_data_offset, 3, ENC_BIG_ENDIAN); proto_tree_add_item(cfm_tlv_tree, hf_tlv_org_spec_subtype, tvb, tlv_data_offset + 3, 1, ENC_NA); // TODO: introduce subdissector table for this proto_tree_add_item(cfm_tlv_tree, hf_tlv_org_spec_value, tvb, tlv_data_offset + 4, cfm_tlv_length-4, ENC_NA); } else { // TODO: report error } tlv_data_offset += cfm_tlv_length; break; case TEST_TLV: { guint32 tlv_tst_test_pattern_type; proto_tree_add_item_ret_uint(cfm_tlv_tree, hf_tlv_tst_test_pattern_type, tvb, tlv_data_offset, 1, ENC_NA, &tlv_tst_test_pattern_type); tlv_data_offset += 1; if (cfm_tlv_length > 1) { switch (tlv_tst_test_pattern_type) { case 0: case 2: default: proto_tree_add_item(cfm_tlv_tree, hf_tlv_tst_test_pattern, tvb, tlv_data_offset, cfm_tlv_length - 1, ENC_NA); tlv_data_offset += cfm_tlv_length - 1; break; case 1: case 3: proto_tree_add_item(cfm_tlv_tree, hf_tlv_tst_test_pattern, tvb, tlv_data_offset, cfm_tlv_length - 5, ENC_NA); tlv_data_offset += cfm_tlv_length - 5; // TODO: look at using proto_tree_add_checksum() proto_tree_add_item(cfm_tlv_tree, hf_tlv_tst_CRC32, tvb, tlv_data_offset, 4, ENC_NA); tlv_data_offset += 4; break; } } else { // TODO: report error } break; } case TGT_MEP_MIP_ID_TLV: case RPL_MEP_MIP_ID_TLV: { guint32 mep_mip_id_subtype; proto_tree_add_item_ret_uint(cfm_tlv_tree, hf_tlv_tgt_rpl_mep_mip_id_subtype, tvb, tlv_data_offset, 1, ENC_NA, &mep_mip_id_subtype); tlv_data_offset += 1; if (cfm_tlv_length > 1) { switch (mep_mip_id_subtype) { case 0x00: // Discovery ingress/node MEP/MIP case 0x01: // Discovery egress MEP/MIP proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_padding, tvb, tlv_data_offset, cfm_tlv_length - 1, ENC_NA); break; case 0x02: // MEP ID proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_mep_id, tvb, tlv_data_offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_padding, tvb, tlv_data_offset + 2, cfm_tlv_length - 3, ENC_NA); break; case 0x03: // MIP ID proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_mip_id_icc, tvb, tlv_data_offset, 6, ENC_ASCII|ENC_NA); proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_mip_id_node_id, tvb, tlv_data_offset + 6, 4, ENC_BIG_ENDIAN); proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_mip_id_if_num, tvb, tlv_data_offset + 10, 4, ENC_BIG_ENDIAN); proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_mip_id_cc, tvb, tlv_data_offset + 14, 2, ENC_ASCII|ENC_NA); proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_padding, tvb, tlv_data_offset + 16, cfm_tlv_length - 17, ENC_NA); break; default: proto_tree_add_item(cfm_tlv_tree, hf_tlv_tgt_rpl_padding, tvb, tlv_data_offset, cfm_tlv_length - 1, ENC_NA); break; } tlv_data_offset += cfm_tlv_length; } else { // TODO: report error } break; } case REQ_MEP_ID_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_req_mep_id_lb, tvb, tlv_data_offset, 1, ENC_NA); tlv_data_offset += 1; tlv_data_offset = dissect_mep_maid(tvb, pinfo, cfm_tlv_tree, tlv_data_offset); proto_tree_add_item(cfm_tlv_tree, hf_tlv_req_mep_id_reserved, tvb, tlv_data_offset, 2, ENC_NA); tlv_data_offset += 2; break; case TEST_ID_TLV: proto_tree_add_item(cfm_tlv_tree, hf_tlv_tst_id_test_id, tvb, tlv_data_offset, 4, ENC_NA); tlv_data_offset += 4; break; default: // TODO: report error proto_tree_add_item(cfm_tlv_tree, hf_tlv_unknown_data, tvb, tlv_data_offset, cfm_tlv_length, ENC_NA); tlv_data_offset += cfm_tlv_length; break; } // TODO: add check here that matches tlv_data_offset to cfm_tlv_offset + cfm_tlv_length cfm_tlv_offset = tlv_data_offset; } while (TRUE); proto_item_set_len(cfm_all_tlvs_ti, cfm_tlv_offset - cfm_first_tlv_offset); proto_item_set_len(ti, cfm_tlv_offset); return cfm_tlv_offset; } /* Register CFM EOAM protocol */ void proto_register_cfm(void) { static hf_register_info hf[] = { /* CFM Common header */ { &hf_cfm_md_level, { "CFM MD Level", "cfm.md_level", FT_UINT8, BASE_DEC, NULL, 0xe0, "MD level/MEG level", HFILL } }, { &hf_cfm_version, { "CFM Version", "cfm.version", FT_UINT8, BASE_DEC, NULL, 0x1f, NULL, HFILL } }, { &hf_cfm_opcode, { "CFM OpCode", "cfm.opcode", FT_UINT8, BASE_DEC, VALS(opcode_type_name_vals), 0x0, NULL, HFILL } }, { &hf_cfm_flags, { "Flags", "cfm.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_flags_Reserved, { "Reserved", "cfm.flags.reserved", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_first_tlv_offset, { "First TLV Offset", "cfm.first_tlv_offset", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* MEP and MAID */ { &hf_cfm_mep_id, { "Maintenance Association Endpoint Identifier", "cfm.mep_id", FT_UINT16, BASE_DEC, NULL, 0x1FFF, NULL, HFILL } }, { &hf_cfm_maid, { "Maintenance Association Identifier", "cfm.maid", FT_NONE, BASE_NONE, NULL, 0x0, "MEG ID (G.8013/Y.1731)", HFILL } }, { &hf_cfm_maid_md_name_format, { "MD Name Format", "cfm.maid.md_name.format", FT_UINT8, BASE_DEC, VALS(md_name_format_type_vals), 0x0, "Reserved (01) in G.8013/Y.1731", HFILL } }, { &hf_cfm_maid_md_name_length, { "MD Name Length", "cfm.maid.md_name.length", FT_UINT8, BASE_DEC, NULL, 0x0, "MEG ID length (G.8013/Y.1731)", HFILL } }, { &hf_cfm_maid_md_name_string, { "MD Name (String)", "cfm.maid.md_name.string", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_md_name_hex, { "MD Name", "cfm.maid.md_name.hex", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_md_name_mac, { "MD Name (MAC+ID)", "cfm.maid.md_name.mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_md_name_mac_id, { "MD Name (MAC+ID)", "cfm.maid.md_name.mac.id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_ma_name_format, { "Short MA Name (MEG ID) Format", "cfm.maid.ma_name.format", FT_UINT8, BASE_DEC, VALS(ma_name_format_type_vals), 0x0, NULL, HFILL } }, { &hf_cfm_maid_ma_name_length, { "Short MA Name (MEG ID) Length", "cfm.maid.ma_name.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_ma_name_pvid, { "Short MA Name PVID", "cfm.maid.ma_name.pvid", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }, }, { &hf_cfm_maid_ma_name_string, { "Short MA Name", "cfm.maid.ma_name.string", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_ma_name_id, { "Short MA Name ID", "cfm.maid.ma_name.id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }, }, { &hf_cfm_maid_ma_name_vpnid_oui, { "Short MA Name VPN ID OUI", "cfm.maid.ma_name.vpnid.oui", FT_UINT24, BASE_OUI, NULL, 0x0, NULL, HFILL }, }, { &hf_cfm_maid_ma_name_vpnid_index, { "Short MA Name VPN ID index", "cfm.maid.ma_name.vpnid.index", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }, }, { &hf_cfm_maid_ma_name_icc_umc, { "MEG ID ICC", "cfm.maid.ma_name.icc", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_ma_name_cc, { "MEG ID CC", "cfm.maid.ma_name.cc", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_ma_name_hex, { "Short MA Name", "cfm.maid.ma_name.hex", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_maid_padding, { "Zero-Padding", "cfm.ccm.maid.padding", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM CCM*/ { &hf_cfm_ccm_pdu, { "CFM CCM PDU", "cfm.ccm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ccm_flags_RDI, { "RDI", "cfm.ccm.flags.rdi", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL } }, { &hf_cfm_ccm_flags_Traffic, { "Traffic", "cfm.ccm.flags.traffic", FT_UINT8, BASE_DEC, NULL, 0x40, NULL, HFILL } }, { &hf_cfm_ccm_flags_Reserved, { "Reserved", "cfm.ccm.flags.reserved", FT_UINT8, BASE_DEC, NULL, 0x38, NULL, HFILL } }, { &hf_cfm_ccm_flags_Interval, { "Interval Field", "cfm.ccm.flags.interval", FT_UINT8, BASE_DEC, VALS(ccm_interval_field_encoding_vals), 0x07, NULL, HFILL } }, { &hf_cfm_ccm_seq_number, { "Sequence Number", "cfm.ccm.seq_num", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ccm_itu_t_y1731, { "Defined by ITU-T Y.1731", "cfm.ccm.itu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ccm_itu_TxFCf, { "TxFCf", "cfm.ccm.itu.txfcf", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ccm_itu_RxFCb, { "RxFCb", "cfm.ccm.itu.rxfcb", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ccm_itu_TxFCb, { "TxFCb", "cfm.ccm.itu.txfcb", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ccm_itu_reserved, { "Reserved", "cfm.ccm.itu.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM LBM*/ { &hf_cfm_lbm_pdu, { "CFM LBM PDU", "cfm.lbm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_lbm_lbr_transaction_id, { "Loopback Transaction Identifier", "cfm.lbm.lbr.transaction_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* CFM LBR*/ { &hf_cfm_lbr_pdu, { "CFM LBR PDU", "cfm.lbr.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM LTM*/ { &hf_cfm_ltm_pdu, { "CFM LTM PDU", "cfm.ltm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ltm_flags_UseFDBonly, { "UseFDBonly", "cfm.ltm.flags.usefdbonly", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL } }, { &hf_cfm_ltm_flags_Reserved, { "Reserved", "cfm.ltm.flags.reserved", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL } }, { &hf_cfm_ltm_ltr_transaction_id, { "Linktrace Transaction Identifier", "cfm.ltm.ltr.transaction_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ltm_ltr_ttl, { "Linktrace TTL", "cfm.ltm.ltr.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ltm_orig_addr, { "Linktrace Message: Original Address", "cfm.ltm.orig_addr", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ltm_targ_addr, { "Linktrace Message: Target Address", "cfm.ltm.target_addr", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM LTR*/ { &hf_cfm_ltr_pdu, { "CFM LTR PDU", "cfm.ltr.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ltr_flags_UseFDBonly, { "UseFDBonly", "cfm.ltr.flags.usefdbonly", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL } }, { &hf_cfm_ltr_flags_FwdYes, { "FwdYes", "cfm.ltr.flags.fwdyes", FT_UINT8, BASE_DEC, NULL, 0x40, NULL, HFILL } }, { &hf_cfm_ltr_flags_TerminalMEP, { "TerminalMEP", "cfm.ltr.flags.terminalmep", FT_UINT8, BASE_DEC, NULL, 0x20, NULL, HFILL } }, { &hf_cfm_ltr_flags_Reserved, { "Reserved", "cfm.ltr.flags.reserved", FT_UINT8, BASE_DEC, NULL, 0x1F, NULL, HFILL } }, { &hf_cfm_ltr_relay_action, { "Linktrace Reply Relay Action", "cfm.ltr.relay_action", FT_UINT8, BASE_DEC, VALS(relay_action_type_vals), 0x0, NULL, HFILL } }, /* CFM RFM */ { &hf_cfm_rfm_pdu, { "CFM RFM PDU", "cfm.rfm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_rfm_transaction_id, { "RFM Transaction Identifier", "cfm.rfm.transaction_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* CFM SFM */ { &hf_cfm_sfm_pdu, { "CFM SFM PDU", "cfm.sfm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_sfm_transaction_id, { "SFM Transaction Identifier", "cfm.sfm.transaction_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* CFM GNM */ { &hf_cfm_gnm_pdu, { "CFM GNM PDU", "cfm.gnm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_gnm_unknown_flags, { "Unknown flags", "cfm.gnm.unknown.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_gnm_subopcode, { "Sub-OpCode", "cfm.gnm.subopcode", FT_UINT8, BASE_HEX, VALS(gnm_sub_opcode_type_name_vals), 0x0, NULL, HFILL } }, /* CFM BNM*/ { &hf_cfm_bnm_flags_Reserved, { "Reserved", "cfm.bnm.flags.Reserved", FT_UINT8, BASE_DEC, NULL, 0xF8, NULL, HFILL } }, { &hf_cfm_bnm_flags_Period, { "Period", "cfm.bnm.flags.Period", FT_UINT8, BASE_DEC, VALS(cfm_bnm_flags_period_vals), 0x07, NULL, HFILL } }, { &hf_cfm_bnm_pdu, { "CFM BNM PDU", "cfm.bnm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_bnm_nominal_bw, { "Nominal Bandwidth", "cfm.bnm.nominal_bw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_bnm_current_bw, { "Current Bandwidth", "cfm.bnm.current_bw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_bnm_port_id, { "Port ID", "cfm.bnm.port_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* CFM AIS*/ { &hf_cfm_ais_pdu, { "CFM AIS PDU", "cfm.ais.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_ais_flags_Reserved, { "Reserved", "cfm.ais.flags.Reserved", FT_UINT8, BASE_DEC, NULL, 0xF8, NULL, HFILL } }, { &hf_cfm_ais_flags_Period, { "Period", "cfm.ais.flags.Period", FT_UINT8, BASE_DEC, VALS(ais_lck_period_type_vals), 0x07, NULL, HFILL } }, /* CFM LCK */ { &hf_cfm_lck_pdu, { "CFM LCK PDU", "cfm.lck.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_lck_flags_Reserved, { "Reserved", "cfm.lck.flags.Reserved", FT_UINT8, BASE_DEC, NULL, 0xF8, NULL, HFILL } }, { &hf_cfm_lck_flags_Period, { "Period", "cfm.lck.flags.Period", FT_UINT8, BASE_DEC, VALS(ais_lck_period_type_vals), 0x07, NULL, HFILL } }, /* CFM TST */ { &hf_cfm_tst_pdu, { "CFM TST PDU", "cfm.tst.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_tst_sequence_num, { "Sequence Number", "cfm.tst.sequence_num", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* CFM APS */ { &hf_cfm_aps_pdu, { "CFM APS PDU", "cfm.aps.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_aps_req_st, { "Request/State", "cfm.aps.req_st", FT_UINT8, BASE_DEC, VALS(aps_request_state_vals), 0xf0, NULL, HFILL } }, { &hf_cfm_aps_protection_type_A, { "Protection type A", "cfm.aps.protec.type_A", FT_BOOLEAN, 8, TFS(&tfs_aps_protection_type_A), 0x08, NULL, HFILL } }, { &hf_cfm_aps_protection_type_B, { "Protection type B", "cfm.aps.protec.type_B", FT_BOOLEAN, 8, TFS(&tfs_aps_protection_type_B), 0x04, NULL, HFILL } }, { &hf_cfm_aps_protection_type_D, { "Protection type D", "cfm.aps.protec.type_D", FT_BOOLEAN, 8, TFS(&tfs_aps_protection_type_D), 0x02, NULL, HFILL } }, { &hf_cfm_aps_protection_type_R, { "Protection type R", "cfm.aps.protec.type_R", FT_BOOLEAN, 8, TFS(&tfs_aps_protection_type_R), 0x01, NULL, HFILL } }, { &hf_cfm_aps_requested_signal, { "Requested signal", "cfm.aps.req_signal", FT_UINT8, BASE_HEX, VALS(aps_requested_signal_values), 0x0, NULL, HFILL } }, { &hf_cfm_aps_bridged_signal, { "Bridged signal", "cfm.aps.bridged_signal", FT_UINT8, BASE_HEX, VALS(aps_bridged_signal_values), 0x0, NULL, HFILL } }, { &hf_cfm_aps_bridge_type, { "Bridge type", "cfm.aps.bridge_type", FT_UINT8, BASE_HEX, VALS(aps_bridge_type_values), 0x80, NULL, HFILL } }, /* CFM R-APS */ { &hf_cfm_raps_pdu, { "CFM R-APS PDU", "cfm.raps.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_raps_req_st, { "Request/State", "cfm.raps.req_st", FT_UINT8, BASE_HEX, VALS(raps_request_state_values), RAPS_REQ_ST_MASK, NULL, HFILL } }, { &hf_cfm_raps_event_subcode, { "Sub-code", "cfm.raps.event.subcode", FT_UINT8, BASE_HEX, VALS(rasp_event_subcode_vals), RAPS_SUB_CODE_MASK, NULL, HFILL } }, { &hf_cfm_raps_subcode_reserved, { "Reserved", "cfm.raps.subcode.reserved", FT_UINT8, BASE_HEX, NULL, RAPS_SUB_CODE_MASK, NULL, HFILL } }, { &hf_cfm_raps_status, { "R-APS status", "cfm.raps.status", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_raps_status_rb, { "RPL Blocked", "cfm.raps.status.rb", FT_BOOLEAN, 8, TFS(&tfs_rasp_rpl_blocked), 0x80, NULL, HFILL } }, { &hf_cfm_raps_status_dnf, { "Do Not Flush", "cfm.raps.status.dnf", FT_BOOLEAN, 8, TFS(&tfs_rasp_dnf), 0x40, NULL, HFILL } }, { &hf_cfm_raps_status_bpr, { "Blocked Port Reference", "cfm.raps.status.bpr", FT_BOOLEAN, 8, TFS(&tfs_rasp_bpr), 0x20, NULL, HFILL } }, { &hf_cfm_raps_status_reserved_v1, { "Reserved", "cfm.raps.status.reserved_v1", FT_UINT8, BASE_HEX, NULL, 0x3F, NULL, HFILL } }, { &hf_cfm_raps_status_reserved_v2, { "Reserved", "cfm.raps.status.reserved_v2", FT_UINT8, BASE_HEX, NULL, 0x1F, NULL, HFILL } }, { &hf_cfm_raps_node_id, { "R-APS Node ID", "cfm.raps.node_id", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_raps_reserved, { "R-APS Reserved", "cfm.raps.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM MCC */ { &hf_cfm_mcc_pdu, { "CFM MCC PDU", "cfm.mcc.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_mcc_oui, { "OUI", "cfm.mcc.oui", FT_UINT24, BASE_OUI, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_mcc_subopcode, { "Subopcode", "cfm.mcc.subopcode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_mcc_data, { "MCC data", "cfm.mcc.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM LMM */ { &hf_cfm_lmm_pdu, { "CFM LMM PDU", "cfm.lmm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_lmm_lmr_flags_Reserved, { "Reserved", "cfm.lmm.lmr.flags.Reserved", FT_UINT8, BASE_HEX, NULL, 0xFE, NULL, HFILL } }, { &hf_cfm_lmm_lmr_flags_Type, { "Type", "cfm.lmm.lmr.flags.Type", FT_BOOLEAN, 8, TFS(&tfs_lmm_lmr_type), 0x01, NULL, HFILL } }, { &hf_cfm_lmm_lmr_TxFCf, { "TxFCf", "cfm.lmm.lmr.txfcf", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_lmm_lmr_RxFCf, { "RxFCf", "cfm.lmm.lmr.rxfcf", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_lmm_lmr_TxFCb, { "TxFCb", "cfm.lmm.lmr.txfcb", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* CFM LMR */ { &hf_cfm_lmr_pdu, { "CFM LMR PDU", "cfm.lmr.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM 1DM */ { &hf_cfm_odm_pdu, { "CFM 1DM PDU", "cfm.odm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_odm_dmm_dmr_flags_Reserved, { "Reserved", "cfm.odm.dmm.dmr.flags.Reserved", FT_UINT8, BASE_HEX, NULL, 0xFE, NULL, HFILL } }, { &hf_cfm_odm_dmm_dmr_flags_Type, { "Type", "cfm.odm.dmm.dmr.flags.Type", FT_BOOLEAN, 8, TFS(&tfs_odm_dmm_dmr_type), 0x01, NULL, HFILL } }, { &hf_cfm_odm_dmm_dmr_TxTimestampf, { "TxTimestampf", "cfm.odm.dmm.dmr.txtimestampf", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_odm_dmm_dmr_RxTimestampf, { "RxTimestampf", "cfm.odm.dmm.dmr.rxtimestampf", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM DMM */ { &hf_cfm_dmm_pdu, { "CFM DMM PDU", "cfm.dmm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_dmm_dmr_TxTimestampb, { "TxTimestampb", "cfm.dmm.dmr.txtimestampb", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_dmm_dmr_RxTimestampb, { "RxTimestampb", "cfm.dmm.dmr.rxtimestampb", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM DMR */ { &hf_cfm_dmr_pdu, { "CFM DMR PDU", "cfm.dmr.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM EXM */ { &hf_cfm_exm_pdu, { "CFM EXM PDU", "cfm.exm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_exm_oui, { "OUI", "cfm.exm.oui", FT_UINT24, BASE_OUI, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_exm_subopcode, { "Subopcode", "cfm.exm.subopcode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_exm_data, { "EXM data", "cfm.exm.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM EXR */ { &hf_cfm_exr_pdu, { "CFM EXR PDU", "cfm.exr.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_exr_oui, { "OUI", "cfm.exr.oui", FT_UINT24, BASE_OUI, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_exr_subopcode, { "Subopcode", "cfm.exr.subopcode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_exr_data, { "EXR data", "cfm.exr.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM VSM */ { &hf_cfm_vsm_pdu, { "CFM VSM PDU", "cfm.vsm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_vsm_oui, { "OUI", "cfm.vsm.oui", FT_UINT24, BASE_OUI, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_vsm_subopcode, { "Subopcode", "cfm.vsm.subopcode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_vsm_data, { "VSM data", "cfm.vsm.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM VSR */ { &hf_cfm_vsr_pdu, { "CFM VSR PDU", "cfm.vsr.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_vsr_oui, { "OUI", "cfm.vsr.oui", FT_UINT24, BASE_OUI, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_vsr_subopcode, { "Subopcode", "cfm.vsr.subopcode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_vsr_data, { "VSR data", "cfm.vsr.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* CFM CSF */ { &hf_cfm_csf_pdu, { "CFM CSF PDU", "cfm.csf.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_csf_flags_Reserved, { "Reserved", "cfm.csf.flags.Reserved", FT_UINT8, BASE_HEX, NULL, 0xC0, NULL, HFILL } }, { &hf_cfm_csf_flags_Type, { "Type", "cfm.csf.flags.Type", FT_UINT8, BASE_DEC, VALS(cfm_csf_flags_type_vals), 0x38, NULL, HFILL } }, { &hf_cfm_csf_flags_Period, { "Type", "cfm.csf.flags.Period", FT_UINT8, BASE_DEC, VALS(cfm_csf_flags_period_vals), 0x07, NULL, HFILL } }, /* CFM 1SL */ { &hf_cfm_osl_pdu, { "CFM 1SL PDU", "cfm.osf.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_osl_src_mep, { "Source MEP ID", "cfm.osl.src_mep_id", FT_UINT16, BASE_DEC, NULL, 0x1FFF, NULL, HFILL } }, { &hf_cfm_osl_reserved, { "1SL Reserved", "cfm.osl.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_osl_testid, { "TestID", "cfm.osl.test_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_osl_txfcf, { "TxFcF", "cfm.osl.txfcf", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* CFM SLM */ { &hf_cfm_slm_pdu, { "CFM SLM PDU", "cfm.slm.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_slm_slr_src_mep, { "Source MEP ID", "cfm.slm.slr.src_mep_id", FT_UINT16, BASE_DEC, NULL, 0x1FFF, NULL, HFILL } }, { &hf_cfm_slm_reserved, { "SLM Reserved", "cfm.slm.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_slm_slr_testid, { "TestID", "cfm.slm.slr.test_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_slm_slr_txfcf, { "TxFcF", "cfm.slm.slr.txfcf", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* CFM SLR */ { &hf_cfm_slr_pdu, { "CFM SLR PDU", "cfm.slr.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_slr_rsp_mep, { "Responder MEP ID", "cfm.slr.rsp_mep_id", FT_UINT16, BASE_DEC, NULL, 0x1FFF, NULL, HFILL } }, { &hf_cfm_slr_txfcb, { "TxFcB", "cfm.slr.txfcb", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* Unknown */ { &hf_cfm_unknown_pdu, { "Unknown PDU", "cfm.unknown.pdu", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_unknown_flags, { "Unknown flags", "cfm.unknown.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_unknown_data, { "Unknown data", "cfm.unknown.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /******************************* TLVs ****************************/ { &hf_cfm_all_tlvs, { "CFM TLVs", "cfm.all_tlvs", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_cfm_tlv_type, { "TLV Type", "cfm.tlv.type", FT_UINT8, BASE_DEC, VALS(tlv_type_field_vals), 0x0, NULL, HFILL } }, { &hf_cfm_tlv_length, { "TLV Length", "cfm.tlv.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* Sender ID TLV */ { &hf_tlv_chassis_id_length, { "Chassis ID Length", "cfm.tlv.sender_id.chassis_id.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_subtype, { "Chassis ID Sub-type", "cfm.tlv.sender_id.chassis_id.subtype", FT_UINT8, BASE_DEC, VALS(sender_id_tlv_chassis_id_subtype_vals), 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_chassis_component, { "Chassis component", "cfm.tlv.sender_id.chassis_id.chassis_component", FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_interface_alias, { "Interface alias", "cfm.tlv.sender_id.chassis_id.intf_alias", FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_port_component, { "Port component", "cfm.tlv.sender_id.chassis_id.port_component", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_mac_address, { "MAC address", "cfm.tlv.sender_id.chassis_id.mac_address", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_network_address_family, { "Network address family", "cfm.tlv.sender_id.chassis_id.network_address.family", FT_UINT8, BASE_DEC, VALS(afn_vals), 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_network_address_ipv4, { "Network address", "cfm.tlv.sender_id.chassis_id.network_address.ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_network_address_ipv6, { "Network address", "cfm.tlv.sender_id.chassis_id.network_address.ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_network_address_unknown, { "Network address", "cfm.tlv.sender_id.chassis_id.network_address.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_interface_name, { "Interface name", "cfm.tlv.sender_id.chassis_id.intf_name", FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_locally_assigned, { "Locally assigned", "cfm.tlv.sender_id.chassis_id.locally_assigned", FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_chassis_id_unknown, { "Unknown", "cfm.tlv.sender_id.chassis_id.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_ma_domain_length, { "Management Address Domain Length", "cfm.tlv.sender_id.ma_domain.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_ma_domain, { "Management Address Domain", "cfm.tlv.sender_id.ma_domain", FT_OID, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_management_addr_length, { "Management Address Length", "cfm.tlv.sender_id.management_addr.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_management_addr_ipv4, { "Management Address", "cfm.tlv.sender_id.management_addr.ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_management_addr_ipv6, { "Management Address", "cfm.tlv.sender_id.management_addr.ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_management_addr_eth, { "Management Address", "cfm.tlv.sender_id.management_addr.eth", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_management_addr_unknown, { "Management Address", "cfm.tlv.sender_id.management_addr.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Port Status TLV */ { &hf_tlv_port_status_value, { "Port Status value", "cfm.tlv.port_status.value", FT_UINT8, BASE_DEC, VALS(port_stat_tlv_vals), 0x0, NULL, HFILL } }, /* Data TLV, Truncated Data TLV, Data Part 1 TLV, Data Part 2 TLV */ { &hf_tlv_data_value, { "Data Value", "cfm.tlv.data.value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Interface status TLV */ { &hf_tlv_interface_status_value, { "Interface Status value", "cfm.tlv.intf_status.value", FT_UINT8, BASE_DEC, VALS(interface_stat_tlv_vals), 0x0, NULL, HFILL } }, /* Reply Ingress TLV, Reply Egress TLV */ { &hf_tlv_reply_ingress_action, { "Ingress Action", "cfm.tlv.reply_ingress.action", FT_UINT8, BASE_DEC, VALS(reply_ingress_tlv_vals), 0x0, NULL, HFILL } }, { &hf_tlv_reply_ingress_mac_address, { "Ingress MAC address", "cfm.tlv.reply_ingress.mac_address", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_length, { "Chassis ID Length", "cfm.tlv.reply_ing_egr.portid.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_subtype, { "Chassis ID Sub-type", "cfm.tlv.reply_ing_egr.portid.subtype", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_interface_alias, { "Interface alias", "cfm.tlv.reply_ing_egr.portid.intf_alias", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_port_component, { "Port component", "cfm.tlv.reply_ing_egr.portid.port_comp", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_mac_address, { "MAC address", "cfm.tlv.reply_ing_egr.portid.mac_address", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_network_address_family, { "Network address family", "cfm.tlv.reply_ing_egr.portid.network_address.family", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_network_address_ipv4, { "Network address", "cfm.tlv.reply_ing_egr.portid.network_address.ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_network_address_ipv6, { "Network address", "cfm.tlv.reply_ing_egr.portid.network_address.ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_network_address_unknown, { "Network address", "cfm.tlv.reply_ing_egr.portid.network_address.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_interface_name, { "Interface name", "cfm.tlv.reply_ing_egr.portid.intf_name", FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_agent_circuit_id, { "Agent circuit ID", "cfm.tlv.reply_ing_egr.portid.agent_circuit_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_locally_assigned, { "Locally assigned", "cfm.tlv.reply_ing_egr.portid.locally_assigned", FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_reply_ing_egr_portid_unknown, { "Chassis ID", "cfm.tlv.reply_ing_egr.portid.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Reply Egress TLV */ { &hf_tlv_reply_egress_action, { "Egress Action", "cfm.tlv.reply_egress.action", FT_UINT8, BASE_DEC, VALS(reply_egress_tlv_vals), 0x0, NULL, HFILL } }, { &hf_tlv_reply_egress_mac_address, { "Egress MAC address", "cfm.tlv.reply_egress.mac_address", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* LTM Egress Identifier TLV */ { &hf_tlv_ltm_egress_id_mac, { "Egress Identifier - MAC of LT Initiator/Responder", "cfm.tlv.ltm_egress.id.mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_ltm_egress_id_unique_identifier, { "Egress Identifier - Unique Identifier", "cfm.tlv.ltm_egress.id.ui", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* LTR Egress Identifier TLV */ { &hf_tlv_ltr_egress_last_id_mac, { "Last Egress Identifier - MAC address", "cfm.tlv.ltr_egress.last_id.mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_ltr_egress_last_id_unique_identifier, { "Last Egress Identifier - Unique Identifier", "cfm.tlv.ltr_egress.last_id.ui", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_ltr_egress_next_id_mac, { "Next Egress Identifier - MAC address", "cfm.tlv.ltr_egress.next_id.mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_ltr_egress_next_id_unique_identifier, { "Next Egress Identifier - Unique Identifier", "cfm.tlv.ltr_egress.next_id.ui", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* PBB-TE TLV */ { &hf_tlv_pbb_te_mip_mac_address, { "MIP MAC address", "cfm.tlv.pbb_te.mip_mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_pbb_te_reverse_vid, { "Reverse VID", "cfm.tlv.pbb_te.reverse_vid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_pbb_te_reverse_mac, { "Reverse MAC", "cfm.tlv.pbb_te.reverse_mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Organization-Specific TLV */ { &hf_tlv_org_spec_oui, { "OUI", "cfm.tlv.org_spec.oui", FT_UINT24, BASE_OUI, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_org_spec_subtype, { "Sub-Type", "cfm.tlv.org_spec.subtype", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_org_spec_value, { "Value", "cfm.tlv.org_spec.value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Test TLV */ { &hf_tlv_tst_test_pattern_type, { "Test Pattern Type", "cfm.tlv.tst.test.pattern.type", FT_UINT8, BASE_DEC, VALS(test_tlv_pattern_type_vals), 0x0, NULL, HFILL } }, { &hf_tlv_tst_test_pattern, { "Test Pattern", "cfm.tlv.tst.test.pattern", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_tst_CRC32, { "CRC-32", "cfm.tlv.tst.crc32", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Target MEP/MIP ID TLV, Replying MEP/MIP ID TLV */ { &hf_tlv_tgt_rpl_mep_mip_id_subtype, { "ID subtype", "cfm.tlv.tgt_rpl_mep_mip.id_subtype", FT_UINT8, BASE_DEC, VALS(mep_mip_id_tlv_subtype_vals), 0x0, NULL, HFILL } }, { &hf_tlv_tgt_rpl_padding, { "Padding", "cfm.tlv.tgt_rpl_mep_mip.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_tgt_rpl_mep_id, { "MEP ID", "cfm.tlv.tgt_rpl_mep_mip.mep_id", FT_UINT16, BASE_DEC, NULL, 0x1FFF, NULL, HFILL } }, { &hf_tlv_tgt_rpl_mip_id_icc, { "ITU-T Carrier Code", "cfm.tlv.tgt_rpl_mep_mip.icc", FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_tgt_rpl_mip_id_node_id, { "Node ID", "cfm.tlv.tgt_rpl_mep_mip.node_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_tgt_rpl_mip_id_if_num, { "IF Num", "cfm.tlv.tgt_rpl_mep_mip.if_num", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_tlv_tgt_rpl_mip_id_cc, { "Country Code", "cfm.tlv.tgt_rpl_mep_mip.cc", FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Requesting MEP ID TLV */ { &hf_tlv_req_mep_id_lb, { "ID subtype", "cfm.tlv.req_mep_id.lb", FT_UINT8, BASE_DEC, VALS(req_mep_id_tlv_lb_vals), 0x0, NULL, HFILL } }, { &hf_tlv_req_mep_id_reserved, { "Reserved", "cfm.tlv.req_mep_id.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Test ID TLV */ { &hf_tlv_tst_id_test_id, { "Test ID", "cfm.tlv.tst_id.test_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* Unknown TLV */ { &hf_tlv_unknown_data, { "TLV Data", "cfm.tlv.unknown.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, }; /* Setup protocol subtree array */ static gint *ett[] = { &ett_cfm, &ett_cfm_flags, &ett_cfm_maid, &ett_cfm_ccm_itu, &ett_cfm_pdu, &ett_cfm_all_tlvs, &ett_cfm_tlv, &ett_cfm_raps_status, }; static ei_register_info ei[] = { { &ei_tlv_tst_id_length, { "cfm.tlv.tst_id.length", PI_PROTOCOL, PI_NOTE, "Test ID TLV length is bits, not octets, unlike other TLVs", EXPFILL } }, { &ei_tlv_management_addr_length, { "cfm.tlv.sender_id.management_addr.length.zero", PI_PROTOCOL, PI_WARN, "Management Address Length should not be present if Management Address Domain Length is 0", EXPFILL } }, }; expert_module_t* expert_cfm; proto_cfm = proto_register_protocol("CFM EOAM IEEE 802.1Q/ITU-T Y.1731 Protocol", "CFM", "cfm"); cfm_handle = register_dissector("cfm", dissect_cfm, proto_cfm); proto_register_field_array(proto_cfm, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_cfm = expert_register_protocol(proto_cfm); expert_register_field_array(expert_cfm, ei, array_length(ei)); } /* Register CFM EOAM protocol handler */ void proto_reg_handoff_cfm(void) { dissector_add_uint("ethertype", ETHERTYPE_CFM, cfm_handle); dissector_add_uint("pwach.channel_type", PW_ACH_TYPE_MPLSTP_OAM, cfm_handle); } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: * * vi: set shiftwidth=8 tabstop=8 noexpandtab: * :indentSize=8:tabSize=8:noTabs=false: */