/* packet-forces.c * RFC 5810 * Routines for dissecting IETF ForCES protocol layer messages.Now support the following TML types:TCP+UDP,SCTP. * Copyright 2009, NDSC & Zhejiang Gongshang University,Fenggen Jia * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include void proto_register_forces(void); void proto_reg_handoff_forces(void); static dissector_handle_t ip_handle; /* Initialize the ForCES protocol and registered fields */ static int proto_forces = -1; /*Main header*/ static int hf_forces_version = -1; static int hf_forces_rsvd = -1; static int hf_forces_messagetype = -1; static int hf_forces_sid = -1; static int hf_forces_did = -1; static int hf_forces_correlator = -1; static int hf_forces_length = -1; /*Flags*/ static int hf_forces_flags= -1; static int hf_forces_flags_ack= -1; static int hf_forces_flags_pri= -1; static int hf_forces_flags_rsrvd= -1; static int hf_forces_flags_em= -1; static int hf_forces_flags_at= -1; static int hf_forces_flags_tp= -1; static int hf_forces_flags_reserved = -1; static int hf_forces_tlv_type = -1; static int hf_forces_tlv_length = -1; /*Initiation of LFBSelect TLV*/ static int hf_forces_lfbselect_tlv_type_lfb_classid = -1; static int hf_forces_lfbselect_tlv_type_lfb_instanceid = -1; /*Initiation of Operation TLV*/ static int hf_forces_lfbselect_tlv_type_operation_type = -1; static int hf_forces_lfbselect_tlv_type_operation_length = -1; static int hf_forces_lfbselect_tlv_type_operation_path_type = -1; static int hf_forces_lfbselect_tlv_type_operation_path_length = -1; static int hf_forces_lfbselect_tlv_type_operation_path_flags = -1; static int hf_forces_lfbselect_tlv_type_operation_path_flags_selector = -1; static int hf_forces_lfbselect_tlv_type_operation_path_flags_reserved = -1; static int hf_forces_lfbselect_tlv_type_operation_path_IDcount = -1; static int hf_forces_lfbselect_tlv_type_operation_path_IDs = -1; static int hf_forces_lfbselect_tlv_type_operation_path_data = -1; /*Initiation of Redirect TLV*/ static int hf_forces_redirect_tlv_meta_data_tlv_type = -1; static int hf_forces_redirect_tlv_meta_data_tlv_length = -1; static int hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv = -1; static int hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_id = -1; static int hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_length = -1; static int hf_forces_redirect_tlv_redirect_data_tlv_type = -1; static int hf_forces_redirect_tlv_redirect_data_tlv_length = -1; /*Initiation of ASResult TLV*/ static int hf_forces_asresult_association_setup_result = -1; /*Initiation of ASTreason TLV*/ static int hf_forces_astreason_tlv_teardown_reason = -1; /*Main TLV may be unknown*/ static int hf_forces_unknown_tlv = -1; /*Message Types */ #define AssociationSetup 0x01 #define AssociationTeardown 0x02 #define Config 0x03 #define Query 0x04 #define EventNotification 0x05 #define PacketRedirect 0x06 #define Heartbeat 0x0F #define AssociationSetupResponse 0x11 #define ConfigResponse 0x13 #define QueryResponse 0x14 /*TLV Types*/ #define Reserved 0x0000 #define REDIRECT_TLV 0x0001 #define ASResult_TLV 0x0010 #define ASTreason_TLV 0x0011 #define LFBselect_TLV 0x1000 #define PATH_DATA_TLV 0x0110 #define KEYINFO_TLV 0x0111 #define FULLDATA_TLV 0x0112 #define SPARSEDATA_TLV 0x0113 #define RESULT_TLV 0x0114 #define METADATA_TLV 0x0115 #define REDIRECTDATA_TLV 0x0116 /*Operation Type*/ #define Reserved 0x0000 #define SET 0x0001 #define SET_PROP 0x0002 #define SET_RESPONSE 0x0003 #define SET_PROP_RESPONSE 0x0004 #define DEL 0x0005 #define DEL_RESPONSE 0x0006 #define GET 0x0007 #define GET_PROP 0x0008 #define GET_RESPONSE 0x0009 #define GET_PROP_RESPONSE 0x000A #define REPORT 0x000B #define COMMIT 0x000C #define COMMIT_RESPONSE 0x000D #define TRCOMP 0x000E #define FLAG_SELECTOR 0x8000 #define ForCES_HEADER_LENGTH 24 #define TLV_TL_LENGTH 4 /*Type+length*/ #define MIN_IP_HEADER_LENGTH 20 /*For TCP+UDP TML. There are two bytes added to the ForCES PL message, not strictly combine to the ForCES protocol. For other type TMLs,no need to add these 2 bytes.*/ #define TCP_UDP_TML_FOCES_MESSAGE_OFFSET_TCP 2 /*SCTP TML*/ static guint forces_alternate_sctp_high_prio_channel_port = 0; static guint forces_alternate_sctp_med_prio_channel_port = 0; static guint forces_alternate_sctp_low_prio_channel_port = 0; /*Initialize the subtree pointers*/ static gint ett_forces = -1; static gint ett_forces_main_header = -1; static gint ett_forces_flags = -1; static gint ett_forces_tlv = -1; static gint ett_forces_lfbselect_tlv_type = -1; /*Operation TLV subtree*/ static gint ett_forces_lfbselect_tlv_type_operation = -1; static gint ett_forces_lfbselect_tlv_type_operation_path = -1; static gint ett_forces_lfbselect_tlv_type_operation_path_data = -1; static gint ett_forces_lfbselect_tlv_type_operation_path_data_path = -1; static gint ett_forces_path_data_tlv = -1; static gint ett_forces_path_data_tlv_flags = -1; /*Selector subtree*/ static gint ett_forces_lfbselect_tlv_type_operation_path_selector = -1; /*Redirect TLV subtree*/ static gint ett_forces_redirect_tlv_type = -1; static gint ett_forces_redirect_tlv_meta_data_tlv = -1; static gint ett_forces_redirect_tlv_meta_data_tlv_meta_data_ilv = -1; static gint ett_forces_redirect_tlv_redirect_data_tlv = -1; /*ASResult TLV subtree*/ static gint ett_forces_asresult_tlv = -1; /*ASReason subtree*/ static gint ett_forces_astreason_tlv = -1; /*Main_TLV unknown subtree*/ static gint ett_forces_unknown_tlv = -1; static expert_field ei_forces_length = EI_INIT; static expert_field ei_forces_tlv_type = EI_INIT; static expert_field ei_forces_tlv_length = EI_INIT; static expert_field ei_forces_lfbselect_tlv_type_operation_path_length = EI_INIT; static expert_field ei_forces_lfbselect_tlv_type_operation_type = EI_INIT; static expert_field ei_forces_redirect_tlv_redirect_data_tlv_length = EI_INIT; /*ACK values and the strings to be displayed*/ static const value_string main_header_flags_ack_vals[] = { { 0x0, "NoACK" }, { 0x1, "SuccessACK" }, { 0x2, "FailureACK" }, { 0x3, "AlwaysACK" }, { 0, NULL} }; /*Execution mode(EM) values and the strings to be displayed*/ static const value_string main_header_flags_em_vals[] = { { 0x0, "Reserved" }, { 0x1, "Execute-all-or-none" }, { 0x2, "Execute-until-failure" }, { 0x3, "Continue-execute-on-failure" }, { 0, NULL} }; /*Transaction Phase values and the strings to be displayed*/ static const value_string main_header_flags_tp_vals[] = { { 0x0, "SOT (Start of Transaction)" }, { 0x1, "MOT (Middle of Transaction)" }, { 0x2, "EOT (End of Transaction)" }, { 0x3, "ABT (Abort)" }, { 0, NULL} }; /*Atomic Transaction(AT) values and the strings to be displayed*/ static const value_string main_header_flags_at_vals[] = { { 0x0, "Stand-alone Message"}, { 0x1, "2PC Transaction Message"}, { 0, NULL} }; /*Association Setup Result*/ static const value_string association_setup_result_at_vals[] = { { 0x0, "success"}, { 0x1, "FE ID invalid"}, { 0x2, "permission denied"}, { 0, NULL}, }; /*Teardown Reason*/ static const value_string teardown_reason_at_vals[] = { { 0x0, "normal-teardown by administrator"}, { 0x1, "error - loss of heartbeats"}, { 0x2, "error - out of bandwidth"}, { 0x3, "error - out of memory"}, { 0x4, "error - application crash"}, { 0x255, "error - other or unspecified"}, { 0, NULL}, }; static const value_string message_type_vals[] = { { AssociationSetup, "AssociationSetup" }, { AssociationTeardown, "AssociationTeardown" }, { Config, "Config" }, { Query, "Query" }, { EventNotification, "EventNotification" }, { PacketRedirect, "PacketRedirect" }, { Heartbeat, "Heartbeat" }, { AssociationSetupResponse, "AssociationSetupResponse" }, { ConfigResponse, "ConfigResponse" }, { QueryResponse, "QueryResponse" }, { 0, NULL}, }; static const value_string tlv_type_vals[] = { { REDIRECT_TLV, "REDIRECT-TLV" }, { ASResult_TLV, "ASResult-TLV" }, { ASTreason_TLV, "ASTreason-TLV" }, { LFBselect_TLV, "LFBselect-TLV" }, { PATH_DATA_TLV, "PATH DATA-TLV" }, { KEYINFO_TLV, "KEYINFO-TLV" }, { FULLDATA_TLV, "FULLDATA-TLV" }, { SPARSEDATA_TLV, "SPARSEDATA-TLV" }, { RESULT_TLV, "RESULT-TLV" }, { METADATA_TLV, "METADATA-TLV" }, { REDIRECTDATA_TLV, "REDIRECTDATA-TLV" }, { 0, NULL}, }; static const value_string operation_type_vals[] = { { Reserved, "Reserved" }, { SET, "SET" }, { SET_PROP, "SET-PROP" }, { SET_RESPONSE, "SET-RESPONSE" }, { SET_PROP_RESPONSE, "SET-PROP-RESPONSE" }, { DEL, "DEL" }, { DEL_RESPONSE, "DEL-RESPONSE" }, { GET, "GET" }, { GET_PROP, "GET-PROP" }, { GET_RESPONSE, "GET-RESPONSE" }, { GET_PROP_RESPONSE, "GET-PROP-RESPONSE" }, { REPORT, "REPORT" }, { COMMIT, "COMMIT" }, { COMMIT_RESPONSE, "COMMIT-RESPONSE" }, { TRCOMP, "TRCOMP" }, { 0, NULL}, }; static void dissect_path_data_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset) { proto_item *ti, *flag_item; guint length_TLV, IDcount, i; guint16 type, flag; proto_tree *tlv_tree, *path_data_tree, *flag_tree; while (tvb_reported_length_remaining(tvb, offset) >= TLV_TL_LENGTH) { tlv_tree = proto_tree_add_subtree(tree, tvb, offset, TLV_TL_LENGTH, ett_forces_path_data_tlv, &ti, "TLV"); type = tvb_get_ntohs(tvb, offset); proto_tree_add_item(tlv_tree, hf_forces_lfbselect_tlv_type_operation_path_type, tvb, offset, 2, ENC_BIG_ENDIAN); length_TLV = tvb_get_ntohs(tvb, offset+2); proto_tree_add_item(tlv_tree, hf_forces_lfbselect_tlv_type_operation_path_length, tvb, offset+2, 2, ENC_BIG_ENDIAN); if (length_TLV < TLV_TL_LENGTH) { expert_add_info_format(pinfo, ti, &ei_forces_lfbselect_tlv_type_operation_path_length, "Bogus TLV length: %u", length_TLV); break; } proto_item_set_len(ti, length_TLV); if (type == PATH_DATA_TLV) { path_data_tree = proto_tree_add_subtree(tree, tvb, offset+TLV_TL_LENGTH, length_TLV-TLV_TL_LENGTH, ett_forces_path_data_tlv, NULL, "Path Data TLV"); flag = tvb_get_ntohs(tvb, offset+TLV_TL_LENGTH); flag_item = proto_tree_add_item(path_data_tree, hf_forces_lfbselect_tlv_type_operation_path_flags, tvb, offset+TLV_TL_LENGTH, 2, ENC_BIG_ENDIAN); flag_tree = proto_item_add_subtree(flag_item, ett_forces_path_data_tlv_flags); proto_tree_add_item(flag_tree, hf_forces_lfbselect_tlv_type_operation_path_flags_selector, tvb, offset+TLV_TL_LENGTH, 2, ENC_BIG_ENDIAN); proto_tree_add_item(flag_tree, hf_forces_lfbselect_tlv_type_operation_path_flags_reserved, tvb, offset+TLV_TL_LENGTH, 2, ENC_BIG_ENDIAN); IDcount = tvb_get_ntohs(tvb, offset + TLV_TL_LENGTH + 2); proto_tree_add_item(path_data_tree, hf_forces_lfbselect_tlv_type_operation_path_IDcount, tvb, offset+TLV_TL_LENGTH+2, 2, ENC_BIG_ENDIAN); for (i = 0; i < IDcount; i++) proto_tree_add_item(path_data_tree, hf_forces_lfbselect_tlv_type_operation_path_IDs, tvb, offset+TLV_TL_LENGTH+2+(i*4), 4, ENC_BIG_ENDIAN); } else { flag = 0; proto_tree_add_item(tree, hf_forces_lfbselect_tlv_type_operation_path_data, tvb, offset+TLV_TL_LENGTH, length_TLV-TLV_TL_LENGTH, ENC_NA); } if ((flag & FLAG_SELECTOR) == 0) break; offset += length_TLV; } } static void dissect_operation_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint length_count) { proto_item *ti; proto_tree *oper_tree; guint type, length; while (tvb_reported_length_remaining(tvb, offset) >= TLV_TL_LENGTH) { oper_tree = proto_tree_add_subtree(tree, tvb, offset, length_count, ett_forces_lfbselect_tlv_type_operation, &ti, "Operation TLV"); type = tvb_get_ntohs(tvb,offset); ti = proto_tree_add_item(oper_tree, hf_forces_lfbselect_tlv_type_operation_type, tvb, offset, 2, ENC_BIG_ENDIAN); if (try_val_to_str(type, operation_type_vals) == NULL) expert_add_info_format(pinfo, ti, &ei_forces_lfbselect_tlv_type_operation_type, "Bogus: ForCES Operation TLV (Type:0x%04x) is not supported", type); proto_tree_add_item_ret_uint(oper_tree, hf_forces_lfbselect_tlv_type_operation_length, tvb, offset+2, 2, ENC_BIG_ENDIAN, &length); dissect_path_data_tlv(tvb, pinfo, oper_tree, offset+TLV_TL_LENGTH); if (length == 0) break; offset += length; } } static void dissect_lfbselecttlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint length_count) { guint tlv_length; proto_tree_add_item(tree, hf_forces_lfbselect_tlv_type_lfb_classid, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(tree, hf_forces_lfbselect_tlv_type_lfb_instanceid, tvb, offset+4, 4, ENC_BIG_ENDIAN); offset += 8; while ((tvb_reported_length_remaining(tvb, offset) > TLV_TL_LENGTH) && (length_count > 12)) { tlv_length = tvb_get_ntohs(tvb, offset+2); dissect_operation_tlv(tvb, pinfo, tree, offset, tlv_length); if (tlv_length == 0) break; offset += tlv_length; } } static void dissect_redirecttlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset) { proto_tree *meta_data_tree, *meta_data_ilv_tree, *redirect_data_tree; gint start_offset; gint length_meta, length_ilv, length_redirect; proto_item *ti; address src_addr, src_net_addr; address dst_addr, dst_net_addr; copy_address_shallow(&src_addr, &pinfo->src); copy_address_shallow(&src_net_addr, &pinfo->net_src); copy_address_shallow(&dst_addr, &pinfo->dst); copy_address_shallow(&dst_net_addr, &pinfo->net_dst); meta_data_tree = proto_tree_add_subtree(tree, tvb, offset, TLV_TL_LENGTH, ett_forces_redirect_tlv_meta_data_tlv, &ti, "Meta Data TLV"); proto_tree_add_item(meta_data_tree, hf_forces_redirect_tlv_meta_data_tlv_type, tvb, offset, 2, ENC_BIG_ENDIAN); length_meta = tvb_get_ntohs(tvb, offset+2); proto_tree_add_uint(meta_data_tree, hf_forces_redirect_tlv_meta_data_tlv_length, tvb, offset+2, 2, length_meta); proto_item_set_len(ti, length_meta); start_offset = offset; while ((tvb_reported_length_remaining(tvb, offset) >= 8) && (start_offset+length_meta > offset)) { meta_data_ilv_tree = proto_tree_add_subtree(tree, tvb, offset, TLV_TL_LENGTH, ett_forces_redirect_tlv_meta_data_tlv_meta_data_ilv, &ti, "Meta Data ILV"); proto_tree_add_item(meta_data_ilv_tree, hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_id, tvb, offset+8, 4, ENC_BIG_ENDIAN); length_ilv = tvb_get_ntohl(tvb, offset+12); proto_tree_add_uint(meta_data_ilv_tree, hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_length, tvb, offset+12, 4, length_ilv); offset += 8; if (length_ilv > 0) { proto_tree_add_item(meta_data_ilv_tree, hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv, tvb, offset, length_ilv, ENC_NA); if (offset + length_ilv > offset) { offset += length_ilv; } } proto_item_set_len(ti, length_ilv + 8); } if (tvb_reported_length_remaining(tvb, offset) > 0) { redirect_data_tree = proto_tree_add_subtree(tree, tvb, offset, TLV_TL_LENGTH, ett_forces_redirect_tlv_redirect_data_tlv, &ti, "Redirect Data TLV"); proto_tree_add_item(redirect_data_tree, hf_forces_redirect_tlv_redirect_data_tlv_type, tvb, offset, 2, ENC_BIG_ENDIAN); length_redirect = tvb_get_ntohs(tvb, offset+2); proto_tree_add_uint(redirect_data_tree, hf_forces_redirect_tlv_redirect_data_tlv_length, tvb, offset+2, 2, length_redirect); if (tvb_reported_length_remaining(tvb, offset) < length_redirect) { expert_add_info_format(pinfo, ti, &ei_forces_redirect_tlv_redirect_data_tlv_length, "Bogus: Redirect Data TLV length (%u bytes) is wrong", length_redirect); } else if (length_redirect < TLV_TL_LENGTH + MIN_IP_HEADER_LENGTH) { expert_add_info_format(pinfo, ti, &ei_forces_redirect_tlv_redirect_data_tlv_length, "Bogus: Redirect Data TLV length (%u bytes) not big enough for IP layer", length_redirect); } else { tvbuff_t *next_tvb; next_tvb = tvb_new_subset_length(tvb, offset+4, length_redirect-TLV_TL_LENGTH); call_dissector(ip_handle, next_tvb, pinfo, redirect_data_tree); /* Restore IP info */ copy_address_shallow(&pinfo->src, &src_addr); copy_address_shallow(&pinfo->net_src, &src_net_addr); copy_address_shallow(&pinfo->dst, &dst_addr); copy_address_shallow(&pinfo->net_dst, &dst_net_addr); } } } static void dissect_forces(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti, *tlv_item; proto_tree *forces_tree, *forces_flags_tree; proto_tree *forces_main_header_tree, *forces_tlv_tree, *tlv_tree; gint length_count; guint8 message_type; guint16 tlv_type; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "ForCES"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_forces, tvb, 0, -1, ENC_NA); forces_tree = proto_item_add_subtree(ti, ett_forces); forces_main_header_tree = proto_tree_add_subtree(forces_tree, tvb, 0, ForCES_HEADER_LENGTH, ett_forces_main_header, NULL, "Common Header"); proto_tree_add_item(forces_main_header_tree, hf_forces_version, tvb, 0, 1, ENC_BIG_ENDIAN); proto_tree_add_item(forces_main_header_tree, hf_forces_rsvd, tvb, 0, 1, ENC_BIG_ENDIAN); message_type = tvb_get_guint8(tvb, offset+1); proto_tree_add_item( forces_main_header_tree, hf_forces_messagetype, tvb, offset+1, 1, ENC_BIG_ENDIAN); length_count = tvb_get_ntohs(tvb, offset+2) * 4; /*multiply 4 DWORD*/ ti = proto_tree_add_uint_format( forces_main_header_tree, hf_forces_length, tvb, offset+2, 2, length_count, "Length: %u Bytes", length_count); if (length_count != tvb_reported_length_remaining(tvb, offset)) expert_add_info_format(pinfo, ti, &ei_forces_length, "Bogus: ForCES Header length (%u bytes) is wrong),should be (%u bytes)", length_count, tvb_reported_length_remaining(tvb, offset)); if (length_count < 24) expert_add_info_format(pinfo, ti, &ei_forces_length, "Bogus: ForCES Header length (%u bytes) is less than 24bytes)", length_count); col_add_fstr(pinfo->cinfo, COL_INFO, "Message Type: %s, Total Length: %u Bytes", val_to_str(message_type, message_type_vals, "Unknown messagetype 0x%x"), length_count); proto_tree_add_item( forces_main_header_tree, hf_forces_sid, tvb, offset+4, 4, ENC_BIG_ENDIAN); proto_tree_add_item( forces_main_header_tree, hf_forces_did, tvb, offset+8, 4, ENC_BIG_ENDIAN); proto_tree_add_item( forces_main_header_tree, hf_forces_correlator, tvb, offset+12, 8, ENC_BIG_ENDIAN); /*Add flags tree*/ ti = proto_tree_add_item(forces_main_header_tree, hf_forces_flags, tvb, offset+20, 4, ENC_BIG_ENDIAN); forces_flags_tree = proto_item_add_subtree(ti, ett_forces_flags); proto_tree_add_item(forces_flags_tree, hf_forces_flags_ack, tvb, offset+20, 4, ENC_BIG_ENDIAN); proto_tree_add_item(forces_flags_tree, hf_forces_flags_at, tvb, offset+20, 4, ENC_BIG_ENDIAN); proto_tree_add_item(forces_flags_tree, hf_forces_flags_em, tvb, offset+20, 4, ENC_BIG_ENDIAN); proto_tree_add_item(forces_flags_tree, hf_forces_flags_pri, tvb, offset+20, 4, ENC_BIG_ENDIAN); proto_tree_add_item(forces_flags_tree, hf_forces_flags_reserved, tvb, offset+20, 4, ENC_BIG_ENDIAN); proto_tree_add_item(forces_flags_tree, hf_forces_flags_rsrvd, tvb, offset+20, 4, ENC_BIG_ENDIAN); proto_tree_add_item(forces_flags_tree, hf_forces_flags_tp, tvb, offset+20, 4, ENC_BIG_ENDIAN); offset += 24; while (tvb_reported_length_remaining(tvb, offset) >= TLV_TL_LENGTH) { forces_tlv_tree = proto_tree_add_subtree(forces_tree, tvb, offset, TLV_TL_LENGTH, ett_forces_tlv, &ti, "TLV"); tlv_type = tvb_get_ntohs(tvb, offset); tlv_item = proto_tree_add_item(forces_tlv_tree, hf_forces_tlv_type, tvb, offset, 2, ENC_BIG_ENDIAN); length_count = tvb_get_ntohs(tvb, offset+2) * 4; proto_item_set_len(ti, length_count); ti = proto_tree_add_uint(forces_tlv_tree, hf_forces_tlv_length, tvb, offset+2, 2, length_count); if (tvb_reported_length_remaining(tvb, offset) < length_count) expert_add_info_format(pinfo, ti, &ei_forces_tlv_length, "Bogus: Main TLV length (%u bytes) is wrong", length_count); if (length_count < TLV_TL_LENGTH) { expert_add_info_format(pinfo, ti, &ei_forces_tlv_length, "Bogus TLV length: %u", length_count); break; } offset += TLV_TL_LENGTH; length_count -= TLV_TL_LENGTH; switch(tlv_type) { case LFBselect_TLV: tlv_tree = proto_tree_add_subtree(forces_tlv_tree, tvb, offset, length_count, ett_forces_lfbselect_tlv_type, NULL, "LFB select TLV"); dissect_lfbselecttlv(tvb, pinfo, tlv_tree, offset, length_count); break; case REDIRECT_TLV: tlv_tree = proto_tree_add_subtree(forces_tlv_tree, tvb, offset, length_count, ett_forces_redirect_tlv_type, NULL, "Redirect TLV"); dissect_redirecttlv(tvb, pinfo, tlv_tree, offset); break; case ASResult_TLV: tlv_tree = proto_tree_add_subtree(forces_tlv_tree, tvb, offset, length_count, ett_forces_asresult_tlv, NULL, "ASResult TLV"); proto_tree_add_item(tlv_tree, hf_forces_asresult_association_setup_result, tvb, offset, 4, ENC_BIG_ENDIAN); break; case ASTreason_TLV: tlv_tree = proto_tree_add_subtree(forces_tlv_tree, tvb, offset, length_count, ett_forces_astreason_tlv, NULL, "ASTreason TLV"); proto_tree_add_item(tlv_tree, hf_forces_astreason_tlv_teardown_reason, tvb, offset, 4, ENC_BIG_ENDIAN); break; default: expert_add_info(pinfo, tlv_item, &ei_forces_tlv_type); tlv_tree = proto_tree_add_subtree(forces_tlv_tree, tvb, offset, length_count, ett_forces_unknown_tlv, NULL, "Unknown TLV"); proto_tree_add_item(tlv_tree, hf_forces_unknown_tlv, tvb, offset, length_count, ENC_NA); break; } offset += length_count; } } /* Code to actually dissect the TCP packets */ static int dissect_forces_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { dissect_forces(tvb, pinfo, tree, TCP_UDP_TML_FOCES_MESSAGE_OFFSET_TCP); return tvb_captured_length(tvb); } /* Code to actually dissect the ForCES protocol layer packets,like UDP,SCTP and others */ static int dissect_forces_not_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { dissect_forces(tvb, pinfo, tree, 0); return tvb_captured_length(tvb); } void proto_register_forces(void) { module_t *forces_module; expert_module_t* expert_forces; /* Setup list of header fields See Section 1.6.1 for details*/ static hf_register_info hf[] = { { &hf_forces_version, { "Version", "forces.flags.version", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL } }, { &hf_forces_rsvd, { "Rsvd", "forces.flags.rsvd", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL } }, { &hf_forces_messagetype, { "Message Type", "forces.messagetype", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_forces_length, { "Header Length", "forces.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_forces_sid, { "Source ID", "forces.sid", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_forces_did, { "Destination ID", "forces.did", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_forces_correlator, { "Correlator", "forces.correlator", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_forces_tlv_type, { "Type", "forces.tlv.type", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_forces_tlv_length, { "Length", "forces.tlv.length", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, NULL, HFILL } }, /*flags*/ { &hf_forces_flags, { "Flags", "forces.Flags", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_forces_flags_ack, { "ACK indicator", "forces.flags.ack", FT_UINT32, BASE_DEC, VALS(main_header_flags_ack_vals), 0xC0000000, NULL, HFILL } }, { &hf_forces_flags_pri, { "Priority", "forces.flags.pri", FT_UINT32, BASE_DEC, NULL, 0x38000000, NULL, HFILL } }, { &hf_forces_flags_rsrvd, { "Rsrvd", "forces.Flags", FT_UINT32, BASE_DEC,NULL, 0x07000000, NULL, HFILL } }, { &hf_forces_flags_em, { "Execution mode", "forces.flags.em", FT_UINT32, BASE_DEC, VALS(main_header_flags_em_vals), 0x00C00000, NULL, HFILL } }, { &hf_forces_flags_at, { "Atomic Transaction", "forces.flags.at", FT_UINT32, BASE_DEC, VALS(main_header_flags_at_vals), 0x00200000, NULL, HFILL } }, { &hf_forces_flags_tp, { "Transaction phase", "forces.flags.tp", FT_UINT32, BASE_DEC, VALS(main_header_flags_tp_vals), 0x00180000, NULL, HFILL } }, { &hf_forces_flags_reserved, { "Reserved", "forces.flags.reserved", FT_UINT32, BASE_DEC,NULL, 0x0007ffff, NULL, HFILL } }, /*LFBSelectTLV*/ { &hf_forces_lfbselect_tlv_type_lfb_classid, { "Class ID", "forces.lfbselect.tlv.type.lfb.classid", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_lfb_instanceid, { "Instance ID", "forces.fbselect.tlv.type.lfb.instanceid", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /*Operation TLV*/ { &hf_forces_lfbselect_tlv_type_operation_type, { "Type", "forces.lfbselect.tlv.type.operation.type", FT_UINT16, BASE_DEC, VALS(operation_type_vals), 0x0, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_length, { "Length", "forces.lfbselect.tlv.type.operation.length", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_path_type, { "Type", "forces.lfbselect.tlv.type.operation.path.type", FT_UINT16, BASE_DEC, VALS(tlv_type_vals), 0x0, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_path_length, { "Length", "forces.lfbselect.tlv.type.operation.path.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_path_data, { "Data", "forces.lfbselect.tlv.type.operation.path.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_path_flags, {"Path Data Flags", "forces.lfbselect.tlv.type.operation.path.data.flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_path_flags_selector, {"Selector", "forces.lfbselect.tlv.type.operation.path.data.flags.selector", FT_UINT16, BASE_HEX, NULL, 0x80, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_path_flags_reserved, {"Reserved", "forces.lfbselect.tlv.type.operation.path.data.flags.reserved", FT_UINT16, BASE_HEX, NULL, 0x7F, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_path_IDcount, { "Path Data IDcount", "forces.lfbselect.tlv.type.operation.path.data.IDcount", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_forces_lfbselect_tlv_type_operation_path_IDs, { "Path Data IDs", "forces.lfbselect.tlv.type.operation.path.data.IDs", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /*Meta data TLV*/ {&hf_forces_redirect_tlv_meta_data_tlv_type, { "Type", "forces.redirect.tlv.meta.data.tlv.type", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_forces_redirect_tlv_meta_data_tlv_length, { "Length", "forces.redirect.tlv.meta.data.tlv.length", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, NULL, HFILL } }, { &hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv, { "Meta Data ILV", "forces.redirect.tlv.meta.data.tlv.meta.data.ilv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_id, { "ID", "forces.redirect.tlv.meta.data.tlv.meta.data.ilv.id", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_length, { "Length", "forces.redirect.tlv.meta.data.tlv.meta.data.ilv.length", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, NULL, HFILL } }, { &hf_forces_redirect_tlv_redirect_data_tlv_type, { "Type", "forces.redirect.tlv.redirect.data.tlv.type", FT_UINT16, BASE_DEC, VALS(tlv_type_vals), 0x0, NULL, HFILL } }, { &hf_forces_redirect_tlv_redirect_data_tlv_length, { "Length", "forces.redirect.tlv.redirect.data.tlv.length", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, NULL, HFILL } }, { &hf_forces_asresult_association_setup_result, { "Association Setup Result", "forces.teardown.reason", FT_UINT32, BASE_DEC, VALS(association_setup_result_at_vals), 0x0, NULL, HFILL } }, { &hf_forces_astreason_tlv_teardown_reason, { "AStreason TLV TearDown Reason", "forces.astreason.tlv.teardown.reason", FT_UINT32, BASE_DEC, VALS(teardown_reason_at_vals), 0x0, NULL, HFILL } }, { &hf_forces_unknown_tlv, { "Data", "forces.unknown.tlv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } } }; /* Setup protocol subtree array */ static gint *ett[] = { &ett_forces, &ett_forces_main_header, &ett_forces_flags, &ett_forces_tlv, &ett_forces_lfbselect_tlv_type, &ett_forces_lfbselect_tlv_type_operation, &ett_forces_lfbselect_tlv_type_operation_path, &ett_forces_lfbselect_tlv_type_operation_path_data, &ett_forces_lfbselect_tlv_type_operation_path_data_path, &ett_forces_lfbselect_tlv_type_operation_path_selector, &ett_forces_path_data_tlv, &ett_forces_path_data_tlv_flags, &ett_forces_redirect_tlv_type, &ett_forces_redirect_tlv_meta_data_tlv, &ett_forces_redirect_tlv_redirect_data_tlv, &ett_forces_redirect_tlv_meta_data_tlv_meta_data_ilv, &ett_forces_asresult_tlv, &ett_forces_astreason_tlv, &ett_forces_unknown_tlv }; static ei_register_info ei[] = { { &ei_forces_length, { "forces.length.bad", PI_PROTOCOL, PI_WARN, "ForCES Header length is wrong", EXPFILL }}, { &ei_forces_tlv_type, { "forces.tlv.type.unknown", PI_PROTOCOL, PI_WARN, "Bogus: The Main_TLV type is unknown", EXPFILL }}, { &ei_forces_tlv_length, { "forces.tlv.length.bad", PI_PROTOCOL, PI_WARN, "Bogus TLV length", EXPFILL }}, { &ei_forces_lfbselect_tlv_type_operation_path_length, { "forces.lfbselect.tlv.type.operation.path.length.bad", PI_PROTOCOL, PI_WARN, "Bogus TLV length", EXPFILL }}, { &ei_forces_lfbselect_tlv_type_operation_type, { "forces.lfbselect.tlv.type.operation.type.unsupported", PI_PROTOCOL, PI_WARN, "ForCES Operation TLV is not supported", EXPFILL }}, { &ei_forces_redirect_tlv_redirect_data_tlv_length, { "forces.redirect.tlv.redirect.data.tlv.length.bad", PI_PROTOCOL, PI_WARN, "Redirect Data TLV length is wrong", EXPFILL }}, }; /* Register the protocol name and description */ proto_forces = proto_register_protocol("Forwarding and Control Element Separation Protocol", "ForCES", "forces"); /* Required function calls to register the header fields and subtrees used */ proto_register_field_array(proto_forces, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_forces = expert_register_protocol(proto_forces); expert_register_field_array(expert_forces, ei, array_length(ei)); forces_module = prefs_register_protocol(proto_forces,proto_reg_handoff_forces); prefs_register_uint_preference(forces_module, "sctp_high_prio_port", "SCTP High Priority channel port", "Decode packets on this sctp port as ForCES", 10, &forces_alternate_sctp_high_prio_channel_port); prefs_register_uint_preference(forces_module, "sctp_med_prio_port", "SCTP Medium Priority channel port", "Decode packets on this sctp port as ForCES", 10, &forces_alternate_sctp_med_prio_channel_port); prefs_register_uint_preference(forces_module, "sctp_low_prio_port", "SCTP Low Priority channel port", "Decode packets on this sctp port as ForCES", 10, &forces_alternate_sctp_low_prio_channel_port); } void proto_reg_handoff_forces(void) { static gboolean inited = FALSE; static guint alternate_sctp_high_prio_channel_port = 0; /* 6700 */ static guint alternate_sctp_med_prio_channel_port = 0; static guint alternate_sctp_low_prio_channel_port = 0; static dissector_handle_t forces_handle_tcp, forces_handle; if (!inited) { forces_handle_tcp = create_dissector_handle(dissect_forces_tcp, proto_forces); forces_handle = create_dissector_handle(dissect_forces_not_tcp, proto_forces); ip_handle = find_dissector_add_dependency("ip", proto_forces); /* Register TCP port for dissection */ dissector_add_for_decode_as_with_preference("tcp.port", forces_handle_tcp); /* Register UDP port for dissection */ dissector_add_for_decode_as_with_preference("udp.port", forces_handle); inited = TRUE; } /* Register SCTP port for high priority dissection */ if ((alternate_sctp_high_prio_channel_port != 0) && (alternate_sctp_high_prio_channel_port != forces_alternate_sctp_high_prio_channel_port)) dissector_delete_uint("sctp.port", alternate_sctp_high_prio_channel_port, forces_handle); if ((forces_alternate_sctp_high_prio_channel_port != 0) && (alternate_sctp_high_prio_channel_port != forces_alternate_sctp_high_prio_channel_port)) dissector_add_uint("sctp.port", forces_alternate_sctp_high_prio_channel_port, forces_handle); alternate_sctp_high_prio_channel_port = forces_alternate_sctp_high_prio_channel_port; /* Register SCTP port for medium priority dissection */ if ((alternate_sctp_med_prio_channel_port != 0) && (alternate_sctp_med_prio_channel_port != forces_alternate_sctp_med_prio_channel_port)) dissector_delete_uint("sctp.port", alternate_sctp_med_prio_channel_port, forces_handle); if ((forces_alternate_sctp_med_prio_channel_port != 0) && (alternate_sctp_med_prio_channel_port != forces_alternate_sctp_med_prio_channel_port)) dissector_add_uint("sctp.port", forces_alternate_sctp_med_prio_channel_port, forces_handle); alternate_sctp_med_prio_channel_port = forces_alternate_sctp_med_prio_channel_port; /* Register SCTP port for low priority dissection */ if ((alternate_sctp_low_prio_channel_port != 0) && (alternate_sctp_low_prio_channel_port != forces_alternate_sctp_low_prio_channel_port)) dissector_delete_uint("sctp.port", alternate_sctp_low_prio_channel_port, forces_handle); if ((forces_alternate_sctp_low_prio_channel_port != 0) && (alternate_sctp_low_prio_channel_port != forces_alternate_sctp_low_prio_channel_port)) dissector_add_uint("sctp.port", forces_alternate_sctp_low_prio_channel_port, forces_handle); alternate_sctp_low_prio_channel_port = forces_alternate_sctp_low_prio_channel_port; } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */