aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-sccp.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-sccp.c')
-rw-r--r--epan/dissectors/packet-sccp.c2366
1 files changed, 2366 insertions, 0 deletions
diff --git a/epan/dissectors/packet-sccp.c b/epan/dissectors/packet-sccp.c
new file mode 100644
index 0000000000..88dee1a850
--- /dev/null
+++ b/epan/dissectors/packet-sccp.c
@@ -0,0 +1,2366 @@
+/* packet-sccp.c
+ * Routines for Signalling Connection Control Part (SCCP) dissection
+ *
+ * It is hopefully compliant to:
+ * ANSI T1.112.3-1996
+ * ITU-T Q.713 7/1996
+ * YDN 038-1997 (Chinese ITU variant)
+ *
+ * Copyright 2002, Jeff Morriss <jeff.morriss[AT]ulticom.com>
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from packet-m2pa.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+#include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include "packet-mtp3.h"
+#include "prefs.h"
+
+#define SCCP_SI 3
+
+#define MESSAGE_TYPE_OFFSET 0
+#define MESSAGE_TYPE_LENGTH 1
+#define POINTER_LENGTH 1
+#define POINTER_LENGTH_LONG 2
+
+#define MESSAGE_TYPE_CR 0x01
+#define MESSAGE_TYPE_CC 0x02
+#define MESSAGE_TYPE_CREF 0x03
+#define MESSAGE_TYPE_RLSD 0x04
+#define MESSAGE_TYPE_RLC 0x05
+#define MESSAGE_TYPE_DT1 0x06
+#define MESSAGE_TYPE_DT2 0x07
+#define MESSAGE_TYPE_AK 0x08
+#define MESSAGE_TYPE_UDT 0x09
+#define MESSAGE_TYPE_UDTS 0x0a
+#define MESSAGE_TYPE_ED 0x0b
+#define MESSAGE_TYPE_EA 0x0c
+#define MESSAGE_TYPE_RSR 0x0d
+#define MESSAGE_TYPE_RSC 0x0e
+#define MESSAGE_TYPE_ERR 0x0f
+#define MESSAGE_TYPE_IT 0x10
+#define MESSAGE_TYPE_XUDT 0x11
+#define MESSAGE_TYPE_XUDTS 0x12
+/* The below 2 are ITU only */
+#define MESSAGE_TYPE_LUDT 0x13
+#define MESSAGE_TYPE_LUDTS 0x14
+
+/* Same as below but with names typed out */
+static const value_string sccp_message_type_values[] = {
+ { MESSAGE_TYPE_CR, "Connection Request" },
+ { MESSAGE_TYPE_CC, "Connection Confirm" },
+ { MESSAGE_TYPE_CREF, "Connection Refused" },
+ { MESSAGE_TYPE_RLSD, "Released" },
+ { MESSAGE_TYPE_RLC, "Release Complete" },
+ { MESSAGE_TYPE_DT1, "Data Form 1" },
+ { MESSAGE_TYPE_DT2, "Data Form 2" },
+ { MESSAGE_TYPE_AK, "Data Acknowledgement" },
+ { MESSAGE_TYPE_UDT, "Unitdata" },
+ { MESSAGE_TYPE_UDTS, "Unitdata Service" },
+ { MESSAGE_TYPE_ED, "Expedited Data" },
+ { MESSAGE_TYPE_EA, "Expedited Data Acknowledgement" },
+ { MESSAGE_TYPE_RSR, "Reset Request" },
+ { MESSAGE_TYPE_RSC, "Reset Confirmation" },
+ { MESSAGE_TYPE_ERR, "Error" },
+ { MESSAGE_TYPE_IT, "Inactivity Timer" },
+ { MESSAGE_TYPE_XUDT, "Extended Unitdata" },
+ { MESSAGE_TYPE_XUDTS, "Extended Unitdata Service" },
+ { MESSAGE_TYPE_LUDT, "Long Unitdata (ITU)" },
+ { MESSAGE_TYPE_LUDTS, "Long Unitdata Service (ITU)" },
+ { 0, NULL } };
+
+/* Same as above but in acronym form (for the Info column) */
+static const value_string sccp_message_type_acro_values[] = {
+ { MESSAGE_TYPE_CR, "CR" },
+ { MESSAGE_TYPE_CC, "CC" },
+ { MESSAGE_TYPE_CREF, "CREF" },
+ { MESSAGE_TYPE_RLSD, "RLSD" },
+ { MESSAGE_TYPE_RLC, "RLC" },
+ { MESSAGE_TYPE_DT1, "DT1" },
+ { MESSAGE_TYPE_DT2, "DT2" },
+ { MESSAGE_TYPE_AK, "AK" },
+ { MESSAGE_TYPE_UDT, "UDT" },
+ { MESSAGE_TYPE_UDTS, "UDTS" },
+ { MESSAGE_TYPE_ED, "ED" },
+ { MESSAGE_TYPE_EA, "EA" },
+ { MESSAGE_TYPE_RSR, "RSR" },
+ { MESSAGE_TYPE_RSC, "RSC" },
+ { MESSAGE_TYPE_ERR, "ERR" },
+ { MESSAGE_TYPE_IT, "IT" },
+ { MESSAGE_TYPE_XUDT, "XUDT" },
+ { MESSAGE_TYPE_XUDTS, "XUDTS" },
+ { MESSAGE_TYPE_LUDT, "LUDT" },
+ { MESSAGE_TYPE_LUDTS, "LUDTS" },
+ { 0, NULL } };
+
+#define PARAMETER_LENGTH_LENGTH 1
+#define PARAMETER_LONG_DATA_LENGTH_LENGTH 2
+#define PARAMETER_TYPE_LENGTH 1
+
+#define PARAMETER_END_OF_OPTIONAL_PARAMETERS 0x00
+#define PARAMETER_DESTINATION_LOCAL_REFERENCE 0x01
+#define PARAMETER_SOURCE_LOCAL_REFERENCE 0x02
+#define PARAMETER_CALLED_PARTY_ADDRESS 0x03
+#define PARAMETER_CALLING_PARTY_ADDRESS 0x04
+#define PARAMETER_CLASS 0x05
+#define PARAMETER_SEGMENTING_REASSEMBLING 0x06
+#define PARAMETER_RECEIVE_SEQUENCE_NUMBER 0x07
+#define PARAMETER_SEQUENCING_SEGMENTING 0x08
+#define PARAMETER_CREDIT 0x09
+#define PARAMETER_RELEASE_CAUSE 0x0a
+#define PARAMETER_RETURN_CAUSE 0x0b
+#define PARAMETER_RESET_CAUSE 0x0c
+#define PARAMETER_ERROR_CAUSE 0x0d
+#define PARAMETER_REFUSAL_CAUSE 0x0e
+#define PARAMETER_DATA 0x0f
+#define PARAMETER_SEGMENTATION 0x10
+#define PARAMETER_HOP_COUNTER 0x11
+/* The below 2 are ITU only */
+#define PARAMETER_IMPORTANCE 0x12
+#define PARAMETER_LONG_DATA 0x13
+/* ISNI is ANSI only */
+#define PARAMETER_ISNI 0xfa
+
+static const value_string sccp_parameter_values[] = {
+ { PARAMETER_END_OF_OPTIONAL_PARAMETERS, "End of Optional Parameters" },
+ { PARAMETER_DESTINATION_LOCAL_REFERENCE, "Destination Local Reference" },
+ { PARAMETER_SOURCE_LOCAL_REFERENCE, "Source Local Reference" },
+ { PARAMETER_CALLED_PARTY_ADDRESS, "Called Party Address" },
+ { PARAMETER_CALLING_PARTY_ADDRESS, "Calling Party Address" },
+ { PARAMETER_CLASS, "Protocol Class" },
+ { PARAMETER_SEGMENTING_REASSEMBLING, "Segmenting/Reassembling" },
+ { PARAMETER_RECEIVE_SEQUENCE_NUMBER, "Receive Sequence Number" },
+ { PARAMETER_SEQUENCING_SEGMENTING, "Sequencing/Segmenting" },
+ { PARAMETER_CREDIT, "Credit" },
+ { PARAMETER_RELEASE_CAUSE, "Release Cause" },
+ { PARAMETER_RETURN_CAUSE, "Return Cause" },
+ { PARAMETER_RESET_CAUSE, "Reset Cause" },
+ { PARAMETER_ERROR_CAUSE, "Error Cause" },
+ { PARAMETER_REFUSAL_CAUSE, "Refusal Cause" },
+ { PARAMETER_DATA, "Data" },
+ { PARAMETER_SEGMENTATION, "Segmentation" },
+ { PARAMETER_HOP_COUNTER, "Hop Counter" },
+ { PARAMETER_IMPORTANCE, "Importance (ITU)" },
+ { PARAMETER_LONG_DATA, "Long Data (ITU)" },
+ { PARAMETER_ISNI, "Intermediate Signaling Network Identification (ANSI)" },
+ { 0, NULL } };
+
+
+#define END_OF_OPTIONAL_PARAMETERS_LENGTH 1
+#define DESTINATION_LOCAL_REFERENCE_LENGTH 3
+#define SOURCE_LOCAL_REFERENCE_LENGTH 3
+#define PROTOCOL_CLASS_LENGTH 1
+#define RECEIVE_SEQUENCE_NUMBER_LENGTH 1
+#define CREDIT_LENGTH 1
+#define RELEASE_CAUSE_LENGTH 1
+#define RETURN_CAUSE_LENGTH 1
+#define RESET_CAUSE_LENGTH 1
+#define ERROR_CAUSE_LENGTH 1
+#define REFUSAL_CAUSE_LENGTH 1
+#define HOP_COUNTER_LENGTH 1
+#define IMPORTANCE_LENGTH 1
+
+
+/* Parts of the Called and Calling Address parameters */
+/* Address Indicator */
+#define ADDRESS_INDICATOR_LENGTH 1
+#define ITU_RESERVED_MASK 0x80
+#define ANSI_NATIONAL_MASK 0x80
+#define ROUTING_INDICATOR_MASK 0x40
+#define GTI_MASK 0x3C
+#define GTI_SHIFT 2
+#define ITU_SSN_INDICATOR_MASK 0x02
+#define ITU_PC_INDICATOR_MASK 0x01
+#define ANSI_PC_INDICATOR_MASK 0x02
+#define ANSI_SSN_INDICATOR_MASK 0x01
+
+static const value_string sccp_national_indicator_values[] = {
+ { 0x0, "Address coded to International standard" },
+ { 0x1, "Address coded to National standard" },
+ { 0, NULL } };
+
+static const value_string sccp_routing_indicator_values[] = {
+ { 0x0, "Route on GT" },
+ { 0x1, "Route on SSN" },
+ { 0, NULL } };
+
+#define AI_GTI_NO_GT 0x0
+#define ITU_AI_GTI_NAI 0x1
+#define AI_GTI_TT 0x2
+#define ITU_AI_GTI_TT_NP_ES 0x3
+#define ITU_AI_GTI_TT_NP_ES_NAI 0x4
+static const value_string sccp_itu_global_title_indicator_values[] = {
+ { AI_GTI_NO_GT, "No Global Title" },
+ { ITU_AI_GTI_NAI, "Nature of Address Indicator only" },
+ { AI_GTI_TT, "Translation Type only" },
+ { ITU_AI_GTI_TT_NP_ES, "Translation Type, Numbering Plan, and Encoding Scheme included" },
+ { ITU_AI_GTI_TT_NP_ES_NAI, "Translation Type, Numbering Plan, Encoding Scheme, and Nature of Address Indicator included" },
+ { 0, NULL } };
+
+/* #define AI_GTI_NO_GT 0x0 */
+#define ANSI_AI_GTI_TT_NP_ES 0x1
+/* #define AI_GTI_TT 0x2 */
+static const value_string sccp_ansi_global_title_indicator_values[] = {
+ { AI_GTI_NO_GT, "No Global Title" },
+ { ANSI_AI_GTI_TT_NP_ES, "Translation Type, Numbering Plan, and Encoding Scheme included" },
+ { AI_GTI_TT, "Translation Type only" },
+ { 0, NULL } };
+
+static const value_string sccp_ai_pci_values[] = {
+ { 0x1, "Point Code present" },
+ { 0x0, "Point Code not present" },
+ { 0, NULL } };
+
+static const value_string sccp_ai_ssni_values[] = {
+ { 0x1, "SSN present" },
+ { 0x0, "SSN not present" },
+ { 0, NULL } };
+
+#define ADDRESS_SSN_LENGTH 1
+#define INVALID_SSN 0xff
+static const value_string sccp_ssn_values[] = {
+ { 0x00, "SSN not known/not used" },
+ { 0x01, "SCCP management" },
+ { 0x02, "Reserved for ITU-T allocation" },
+ { 0x03, "ISDN User Part" },
+ { 0x04, "OMAP (Operation, Maintenance, and Administration Part)" },
+ { 0x05, "MAP (Mobile Application Part)" },
+ { 0x06, "HLR (Home Location Register)" },
+ { 0x07, "VLR (Visitor Location Register)" },
+ { 0x08, "MSC (Mobile Switching Center)" },
+ { 0x09, "EIC/EIR (Equipment Identifier Center/Equipment Identification Register)" },
+ { 0x0a, "AUC/AC (Authentication Center)" },
+ { 0x0b, "ISDN supplementary services (ITU only)" },
+ { 0x0c, "Reserved for international use (ITU only)" },
+ { 0x0d, "Broadband ISDN edge-to-edge applications (ITU only)" },
+ { 0x0e, "TC test responder (ITU only)" },
+ { 0x8e, "RANAP" },
+ { 0xfc, "IOS" },
+ { 0xfe, "BSSAP/BSAP" },
+ { 0, NULL } };
+
+
+/* * * * * * * * * * * * * * * * *
+ * Global Title: ITU GTI == 0001 *
+ * * * * * * * * * * * * * * * * */
+#define GT_NAI_MASK 0x7F
+#define GT_NAI_LENGTH 1
+static const value_string sccp_nai_values[] = {
+ { 0x00, "NAI unknown" },
+ { 0x01, "Subscriber Number" },
+ { 0x02, "Reserved for national use" },
+ { 0x03, "National significant number" },
+ { 0x04, "International number" },
+ { 0, NULL } };
+
+
+#define GT_OE_MASK 0x80
+#define GT_OE_EVEN 0
+#define GT_OE_ODD 1
+static const value_string sccp_oe_values[] = {
+ { GT_OE_EVEN, "Even number of address signals" },
+ { GT_OE_ODD, "Odd number of address signals" },
+ { 0, NULL } };
+
+#define GT_SIGNAL_LENGTH 1
+#define GT_ODD_SIGNAL_MASK 0x0f
+#define GT_EVEN_SIGNAL_MASK 0xf0
+#define GT_EVEN_SIGNAL_SHIFT 4
+#define GT_MAX_SIGNALS 32
+static const value_string sccp_address_signal_values[] = {
+ { 0, "0" },
+ { 1, "1" },
+ { 2, "2" },
+ { 3, "3" },
+ { 4, "4" },
+ { 5, "5" },
+ { 6, "6" },
+ { 7, "7" },
+ { 8, "8" },
+ { 9, "9" },
+ { 10, "(spare)" },
+ { 11, "11" },
+ { 12, "12" },
+ { 13, "(spare)" },
+ { 14, "(spare)" },
+ { 15, "ST" },
+ { 0, NULL } };
+
+
+/* * * * * * * * * * * * * * * * * * * * *
+ * Global Title: ITU and ANSI GTI == 0010 *
+ * * * * * * * * * * * * * * * * * * * * */
+#define GT_TT_LENGTH 1
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Global Title: ITU GTI == 0011, ANSI GTI == 0001 *
+ * * * * * * * * * * * * * * * * * * * * * * * * * */
+#define GT_NP_MASK 0xf0
+#define GT_NP_ES_LENGTH 1
+static const value_string sccp_np_values[] = {
+ { 0x0, "Unknown" },
+ { 0x1, "ISDN/telephony" },
+ { 0x2, "Generic (ITU)/Reserved (ANSI)" },
+ { 0x3, "Data" },
+ { 0x4, "Telex" },
+ { 0x5, "Maritime mobile" },
+ { 0x6, "Land mobile" },
+ { 0x7, "ISDN/mobile" },
+ { 0xe, "Private network or network-specific" },
+ { 0xf, "Reserved" },
+ { 0, NULL } };
+
+#define GT_ES_MASK 0x0f
+#define GT_ES_UNKNOWN 0x0
+#define GT_ES_BCD_ODD 0x1
+#define GT_ES_BCD_EVEN 0x2
+#define GT_ES_NATIONAL 0x3
+#define GT_ES_RESERVED 0xf
+static const value_string sccp_es_values[] = {
+ { GT_ES_UNKNOWN, "Unknown" },
+ { GT_ES_BCD_ODD, "BCD, odd number of digits" },
+ { GT_ES_BCD_EVEN, "BCD, even number of digits" },
+ { GT_ES_NATIONAL, "National specific" },
+ { GT_ES_RESERVED, "Reserved (ITU)/Spare (ANSI)" },
+ { 0, NULL } };
+
+/* Address signals above */
+
+
+/* * * * * * * * * * * * * * * * *
+ * Global Title: ITU GTI == 0100 *
+ * * * * * * * * * * * * * * * * */
+/* NP above */
+/* ES above */
+/* NAI above */
+/* Address signals above */
+
+
+#define CLASS_CLASS_MASK 0xf
+#define CLASS_SPARE_HANDLING_MASK 0xf0
+static const value_string sccp_class_handling_values [] = {
+ { 0x0, "No special options" },
+ { 0x8, "Return message on error" },
+ { 0, NULL } };
+
+
+#define SEGMENTING_REASSEMBLING_LENGTH 1
+#define SEGMENTING_REASSEMBLING_MASK 0x01
+#define NO_MORE_DATA 0
+#define MORE_DATA 1
+/* This is also used by sequencing-segmenting parameter */
+static const value_string sccp_segmenting_reassembling_values [] = {
+ { NO_MORE_DATA, "No more data" },
+ { MORE_DATA, "More data" },
+ { 0, NULL } };
+
+
+#define RECEIVE_SEQUENCE_NUMBER_LENGTH 1
+#define RSN_MASK 0xfe
+
+#define SEQUENCING_SEGMENTING_LENGTH 2
+#define SEQUENCING_SEGMENTING_SSN_LENGTH 1
+#define SEQUENCING_SEGMENTING_RSN_LENGTH 1
+#define SEND_SEQUENCE_NUMBER_MASK 0xfe
+#define RECEIVE_SEQUENCE_NUMBER_MASK 0xfe
+#define SEQUENCING_SEGMENTING_MORE_MASK 0x01
+
+
+#define CREDIT_LENGTH 1
+
+#define RELEASE_CAUSE_LENGTH 1
+static const value_string sccp_release_cause_values [] = {
+ { 0x00, "End user originated" },
+ { 0x01, "End user congestion" },
+ { 0x02, "End user failure" },
+ { 0x03, "SCCP user originated" },
+ { 0x04, "Remote procedure error" },
+ { 0x05, "Inconsistent connection data" },
+ { 0x06, "Access failure" },
+ { 0x07, "Access congestion" },
+ { 0x08, "Subsystem failure" },
+ { 0x09, "Subsystem congestion" },
+ { 0x0a, "MTP failure" },
+ { 0x0b, "Netowrk congestion" },
+ { 0x0c, "Expiration of reset timer" },
+ { 0x0d, "Expiration of receive inactivity timer" },
+ { 0x0e, "Reserved" },
+ { 0x0f, "Unqualified" },
+ { 0x10, "SCCP failure (ITU only)" },
+ { 0, NULL } };
+
+
+#define RETURN_CAUSE_LENGTH 1
+static const value_string sccp_return_cause_values [] = {
+ { 0x00, "No translation for an address of such nature" },
+ { 0x01, "No translation for this specific address" },
+ { 0x02, "Subsystem congestion" },
+ { 0x03, "Subsystem failure" },
+ { 0x04, "Unequipped failure" },
+ { 0x05, "MTP failure" },
+ { 0x06, "Network congestion" },
+ { 0x07, "Unqualified" },
+ { 0x08, "Error in message transport" },
+ { 0x09, "Error in local processing" },
+ { 0x0a, "Destination cannot perform reassembly" },
+ { 0x0b, "SCCP failure" },
+ { 0x0c, "Hop counter violation" },
+ { 0x0d, "Segmentation not supported (ITU only)" },
+ { 0x0e, "Segmentation failure (ITU only)" },
+ { 0xf9, "Invalid ISNI routing request (ANSI only)"},
+ { 0xfa, "Unauthorized message (ANSI only)" },
+ { 0xfb, "Message incompatibility (ANSI only)" },
+ { 0xfc, "Cannot perform ISNI constrained routing (ANSI only)" },
+ { 0xfd, "Unable to perform ISNI identification (ANSI only)" },
+ { 0, NULL } };
+
+
+#define RESET_CAUSE_LENGTH 1
+static const value_string sccp_reset_cause_values [] = {
+ { 0x00, "End user originated" },
+ { 0x01, "SCCP user originated" },
+ { 0x02, "Message out of order - incorrect send sequence number" },
+ { 0x03, "Message out of order - incorrect receive sequence number" },
+ { 0x04, "Remote procedure error - message out of window" },
+ { 0x05, "Remote procedure error - incorrect send sequence number after (re)initialization" },
+ { 0x06, "Remote procedure error - general" },
+ { 0x07, "Remote end user operational" },
+ { 0x08, "Network operational" },
+ { 0x09, "Access operational" },
+ { 0x0a, "Network congestion" },
+ { 0x0b, "Reserved (ITU)/Not obtainable (ANSI)" },
+ { 0x0c, "Unqualified" },
+ { 0, NULL } };
+
+
+#define ERROR_CAUSE_LENGTH 1
+static const value_string sccp_error_cause_values [] = {
+ { 0x00, "Local Reference Number (LRN) mismatch - unassigned destination LRN" },
+ { 0x01, "Local Reference Number (LRN) mismatch - inconsistent source LRN" },
+ { 0x02, "Point code mismatch" },
+ { 0x03, "Service class mismatch" },
+ { 0x04, "Unqualified" },
+ { 0, NULL } };
+
+
+#define REFUSAL_CAUSE_LENGTH 1
+static const value_string sccp_refusal_cause_values [] = {
+ { 0x00, "End user originated" },
+ { 0x01, "End user congestion" },
+ { 0x02, "End user failure" },
+ { 0x03, "SCCP user originated" },
+ { 0x04, "Destination address unknown" },
+ { 0x05, "Destination inaccessible" },
+ { 0x06, "Network resource - QOS not available/non-transient" },
+ { 0x07, "Network resource - QOS not available/transient" },
+ { 0x08, "Access failure" },
+ { 0x09, "Access congestion" },
+ { 0x0a, "Subsystem failure" },
+ { 0x0b, "Subsystem congestion" },
+ { 0x0c, "Expiration of connection establishment timer" },
+ { 0x0d, "Incompatible user data" },
+ { 0x0e, "Reserved" },
+ { 0x0f, "Unqualified" },
+ { 0x10, "Hop counter violation" },
+ { 0x11, "SCCP failure (ITU only)" },
+ { 0x12, "No translation for an address of such nature" },
+ { 0x13, "Unequipped user" },
+ { 0, NULL } };
+
+
+#define SEGMENTATION_LENGTH 4
+#define SEGMENTATION_FIRST_SEGMENT_MASK 0x80
+#define SEGMENTATION_CLASS_MASK 0x40
+#define SEGMENTATION_SPARE_MASK 0x30
+#define SEGMENTATION_REMAINING_MASK 0x0f
+static const value_string sccp_segmentation_first_segment_values [] = {
+ { 1, "First segment" },
+ { 0, "Not first segment" },
+ { 0, NULL } };
+static const value_string sccp_segmentation_class_values [] = {
+ { 0, "Class 0 selected" },
+ { 1, "Class 1 selected" },
+ { 0, NULL } };
+
+
+#define HOP_COUNTER_LENGTH 1
+
+#define IMPORTANCE_LENGTH 1
+#define IMPORTANCE_IMPORTANCE_MASK 0x7
+
+
+#define ANSI_ISNI_ROUTING_CONTROL_LENGTH 1
+#define ANSI_ISNI_MI_MASK 0x01
+#define ANSI_ISNI_IRI_MASK 0x06
+#define ANSI_ISNI_RES_MASK 0x08
+#define ANSI_ISNI_TI_MASK 0x10
+#define ANSI_ISNI_TI_SHIFT 4
+#define ANSI_ISNI_COUNTER_MASK 0xe0
+
+#define ANSI_ISNI_NETSPEC_MASK 0x03
+
+static const value_string sccp_isni_mark_for_id_values [] = {
+ { 0x0, "Do not identify networks" },
+ { 0x1, "Identify networks" },
+ { 0, NULL } };
+
+static const value_string sccp_isni_iri_values [] = {
+ { 0x0, "Neither constrained nor suggested ISNI routing" },
+ { 0x1, "Constrained ISNI routing" },
+ { 0x2, "Reserved for suggested ISNI routing" },
+ { 0x3, "Spare" },
+ { 0, NULL } };
+
+#define ANSI_ISNI_TYPE_0 0x0
+#define ANSI_ISNI_TYPE_1 0x1
+static const value_string sccp_isni_ti_values [] = {
+ { ANSI_ISNI_TYPE_0, "Type zero ISNI parameter format" },
+ { ANSI_ISNI_TYPE_1, "Type one ISNI parameter format" },
+ { 0, NULL } };
+
+
+/* Initialize the protocol and registered fields */
+static int proto_sccp = -1;
+static int hf_sccp_message_type = -1;
+static int hf_sccp_variable_pointer1 = -1;
+static int hf_sccp_variable_pointer2 = -1;
+static int hf_sccp_variable_pointer3 = -1;
+static int hf_sccp_optional_pointer = -1;
+static int hf_sccp_ssn = -1;
+static int hf_sccp_gt_digits = -1;
+
+/* Called Party address */
+static int hf_sccp_called_national_indicator = -1;
+static int hf_sccp_called_routing_indicator = -1;
+static int hf_sccp_called_itu_global_title_indicator = -1;
+static int hf_sccp_called_ansi_global_title_indicator = -1;
+static int hf_sccp_called_itu_ssn_indicator = -1;
+static int hf_sccp_called_itu_point_code_indicator = -1;
+static int hf_sccp_called_ansi_ssn_indicator = -1;
+static int hf_sccp_called_ansi_point_code_indicator = -1;
+static int hf_sccp_called_ssn = -1;
+static int hf_sccp_called_pc_member = -1;
+static int hf_sccp_called_pc_cluster = -1;
+static int hf_sccp_called_pc_network = -1;
+static int hf_sccp_called_ansi_pc = -1;
+static int hf_sccp_called_chinese_pc = -1;
+static int hf_sccp_called_itu_pc = -1;
+static int hf_sccp_called_gt_nai = -1;
+static int hf_sccp_called_gt_oe = -1;
+static int hf_sccp_called_gt_tt = -1;
+static int hf_sccp_called_gt_np = -1;
+static int hf_sccp_called_gt_es = -1;
+static int hf_sccp_called_gt_digits = -1;
+
+/* Calling party address */
+static int hf_sccp_calling_national_indicator = -1;
+static int hf_sccp_calling_routing_indicator = -1;
+static int hf_sccp_calling_itu_global_title_indicator = -1;
+static int hf_sccp_calling_ansi_global_title_indicator = -1;
+static int hf_sccp_calling_itu_ssn_indicator = -1;
+static int hf_sccp_calling_itu_point_code_indicator = -1;
+static int hf_sccp_calling_ansi_ssn_indicator = -1;
+static int hf_sccp_calling_ansi_point_code_indicator = -1;
+static int hf_sccp_calling_ssn = -1;
+static int hf_sccp_calling_pc_member = -1;
+static int hf_sccp_calling_pc_cluster = -1;
+static int hf_sccp_calling_pc_network = -1;
+static int hf_sccp_calling_ansi_pc = -1;
+static int hf_sccp_calling_chinese_pc = -1;
+static int hf_sccp_calling_itu_pc = -1;
+static int hf_sccp_calling_gt_nai = -1;
+static int hf_sccp_calling_gt_oe = -1;
+static int hf_sccp_calling_gt_tt = -1;
+static int hf_sccp_calling_gt_np = -1;
+static int hf_sccp_calling_gt_es = -1;
+static int hf_sccp_calling_gt_digits = -1;
+
+/* Other parameter values */
+static int hf_sccp_dlr = -1;
+static int hf_sccp_slr = -1;
+static int hf_sccp_class = -1;
+static int hf_sccp_handling = -1;
+static int hf_sccp_more = -1;
+static int hf_sccp_rsn = -1;
+static int hf_sccp_sequencing_segmenting_ssn = -1;
+static int hf_sccp_sequencing_segmenting_rsn = -1;
+static int hf_sccp_sequencing_segmenting_more = -1;
+static int hf_sccp_credit = -1;
+static int hf_sccp_release_cause = -1;
+static int hf_sccp_return_cause = -1;
+static int hf_sccp_reset_cause = -1;
+static int hf_sccp_error_cause = -1;
+static int hf_sccp_refusal_cause = -1;
+static int hf_sccp_segmentation_first = -1;
+static int hf_sccp_segmentation_class = -1;
+static int hf_sccp_segmentation_remaining = -1;
+static int hf_sccp_segmentation_slr = -1;
+static int hf_sccp_hop_counter = -1;
+static int hf_sccp_importance = -1;
+static int hf_sccp_ansi_isni_mi = -1;
+static int hf_sccp_ansi_isni_iri = -1;
+static int hf_sccp_ansi_isni_ti = -1;
+static int hf_sccp_ansi_isni_netspec = -1;
+static int hf_sccp_ansi_isni_counter = -1;
+
+
+/* Initialize the subtree pointers */
+static gint ett_sccp = -1;
+static gint ett_sccp_called = -1;
+static gint ett_sccp_called_ai = -1;
+static gint ett_sccp_called_pc = -1;
+static gint ett_sccp_called_gt = -1;
+static gint ett_sccp_calling = -1;
+static gint ett_sccp_calling_ai = -1;
+static gint ett_sccp_calling_pc = -1;
+static gint ett_sccp_calling_gt = -1;
+static gint ett_sccp_sequencing_segmenting = -1;
+static gint ett_sccp_segmentation = -1;
+static gint ett_sccp_ansi_isni_routing_control = -1;
+
+/*
+ * Here are the global variables associated with
+ * the various user definable characteristics of the dissection
+ */
+static guint32 sccp_source_pc_global = 0;
+static gboolean sccp_show_length = FALSE;
+
+static module_t *sccp_module;
+static heur_dissector_list_t heur_subdissector_list;
+
+/* Keep track of SSN value of current message so if/when we get to the data
+ * parameter, we can call appropriate sub-dissector. TODO: can this info
+ * be stored elsewhere?
+ */
+static guint8 called_ssn = INVALID_SSN;
+static guint8 calling_ssn = INVALID_SSN;
+
+static dissector_handle_t data_handle;
+static dissector_table_t sccp_ssn_dissector_table;
+
+static void
+dissect_sccp_unknown_message(tvbuff_t *message_tvb, proto_tree *sccp_tree)
+{
+ guint32 message_length;
+
+ message_length = tvb_length(message_tvb);
+
+ proto_tree_add_text(sccp_tree, message_tvb, 0, message_length,
+ "Unknown message (%u byte%s)",
+ message_length, plurality(message_length, "", "s"));
+}
+
+static void
+dissect_sccp_unknown_param(tvbuff_t *tvb, proto_tree *tree, guint8 type, guint length)
+{
+ proto_tree_add_text(tree, tvb, 0, length, "Unknown parameter 0x%x (%u byte%s)",
+ type, length, plurality(length, "", "s"));
+}
+
+static void
+dissect_sccp_dlr_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint32 reference;
+
+ reference = tvb_get_letoh24(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_dlr, tvb, 0, length, reference);
+}
+
+static void
+dissect_sccp_slr_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint32 reference;
+
+ reference = tvb_get_letoh24(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_slr, tvb, 0, length, reference);
+}
+
+static void
+dissect_sccp_gt_address_information(tvbuff_t *tvb, proto_tree *tree,
+ guint length, gboolean even_length,
+ gboolean called)
+{
+ guint offset = 0;
+ guint8 odd_signal, even_signal = 0x0f;
+ char gt_digits[GT_MAX_SIGNALS] = { 0 };
+
+ while(offset < length)
+ {
+ odd_signal = tvb_get_guint8(tvb, offset) & GT_ODD_SIGNAL_MASK;
+ even_signal = tvb_get_guint8(tvb, offset) & GT_EVEN_SIGNAL_MASK;
+ even_signal >>= GT_EVEN_SIGNAL_SHIFT;
+
+ strcat(gt_digits, val_to_str(odd_signal, sccp_address_signal_values,
+ "Unknown"));
+
+ /* If the last signal is NOT filler */
+ if (offset != (length - 1) || even_length == TRUE)
+ strcat(gt_digits, val_to_str(even_signal, sccp_address_signal_values,
+ "Unknown"));
+
+ offset += GT_SIGNAL_LENGTH;
+ }
+
+ proto_tree_add_string_format(tree, called ? hf_sccp_called_gt_digits
+ : hf_sccp_calling_gt_digits,
+ tvb, 0, length,
+ gt_digits,
+ "Address information (digits): %s", gt_digits);
+ proto_tree_add_string_hidden(tree, called ? hf_sccp_gt_digits
+ : hf_sccp_gt_digits,
+ tvb, 0, length,
+ gt_digits);
+}
+
+static void
+dissect_sccp_global_title(tvbuff_t *tvb, proto_tree *tree, guint length,
+ guint8 gti, gboolean called)
+{
+ proto_item *gt_item = 0;
+ proto_tree *gt_tree = 0;
+ tvbuff_t *signals_tvb;
+ guint offset = 0;
+ guint8 odd_even, nai, tt, np, es;
+ gboolean even = TRUE;
+
+ /* Shift GTI to where we can work with it */
+ gti >>= GTI_SHIFT;
+
+ gt_item = proto_tree_add_text(tree, tvb, offset, length,
+ "Global Title 0x%x (%u byte%s)",
+ gti, length, plurality(length,"", "s"));
+ gt_tree = proto_item_add_subtree(gt_item, called ? ett_sccp_called_gt
+ : ett_sccp_calling_gt);
+
+ /* Decode Transation Type (if present) */
+ switch (gti) {
+ case AI_GTI_TT:
+
+ /* Protocol doesn't tell us, so we ASSUME even... */
+ even = TRUE;
+ /* Fall through */
+ case ITU_AI_GTI_TT_NP_ES:
+ case ITU_AI_GTI_TT_NP_ES_NAI:
+ case ANSI_AI_GTI_TT_NP_ES:
+
+ tt = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(gt_tree, called ? hf_sccp_called_gt_tt
+ : hf_sccp_calling_gt_tt,
+ tvb, offset, GT_TT_LENGTH, tt);
+ offset += GT_TT_LENGTH;
+ }
+
+ /* Decode Numbering Plan and Encoding Scheme (if present) */
+ switch (gti) {
+ case ITU_AI_GTI_TT_NP_ES:
+ case ITU_AI_GTI_TT_NP_ES_NAI:
+ case ANSI_AI_GTI_TT_NP_ES:
+
+ np = tvb_get_guint8(tvb, offset) & GT_NP_MASK;
+ proto_tree_add_uint(gt_tree, called ? hf_sccp_called_gt_np
+ : hf_sccp_calling_gt_np,
+ tvb, offset, GT_NP_ES_LENGTH, np);
+
+ es = tvb_get_guint8(tvb, offset) & GT_ES_MASK;
+ proto_tree_add_uint(gt_tree, called ? hf_sccp_called_gt_es
+ : hf_sccp_calling_gt_es,
+ tvb, offset, GT_NP_ES_LENGTH, es);
+
+ even = (es == GT_ES_BCD_EVEN) ? TRUE : FALSE;
+
+ offset += GT_NP_ES_LENGTH;
+ }
+
+ /* Decode Odd/Even Indicator (if present) */
+ if (gti == ITU_AI_GTI_NAI) {
+ odd_even = tvb_get_guint8(tvb, offset) & GT_OE_MASK;
+ proto_tree_add_uint(gt_tree, called ? hf_sccp_called_gt_oe
+ : hf_sccp_calling_gt_oe,
+ tvb, offset, GT_NAI_LENGTH, odd_even);
+ even = (odd_even == GT_OE_EVEN) ? TRUE : FALSE;
+
+ /* offset doesn't change */
+ }
+
+ /* Decode Nature of Address Indicator (if present) */
+ switch (gti) {
+ case ITU_AI_GTI_NAI:
+ case ITU_AI_GTI_TT_NP_ES_NAI:
+ nai = tvb_get_guint8(tvb, offset) & GT_NAI_MASK;
+ proto_tree_add_uint(gt_tree, called ? hf_sccp_called_gt_nai
+ : hf_sccp_calling_gt_nai,
+ tvb, offset, GT_NAI_LENGTH, nai);
+
+ offset += GT_NAI_LENGTH;
+ }
+
+ /* Decode address signal(s) */
+ if (length < offset)
+ return;
+ signals_tvb = tvb_new_subset(tvb, offset, (length - offset),
+ (length - offset));
+ dissect_sccp_gt_address_information(signals_tvb, gt_tree, (length - offset),
+ even,
+ called);
+}
+
+static int
+dissect_sccp_3byte_pc(tvbuff_t *tvb, proto_tree *call_tree, guint offset,
+ gboolean called)
+{
+ guint32 dpc;
+ proto_item *call_pc_item = 0;
+ proto_tree *call_pc_tree = 0;
+ char pc[ANSI_PC_STRING_LENGTH];
+ int *hf_pc;
+
+ if (mtp3_standard == ANSI_STANDARD)
+ {
+ if (called)
+ hf_pc = &hf_sccp_called_ansi_pc;
+ else
+ hf_pc = &hf_sccp_calling_ansi_pc;
+ } else /* CHINESE_ITU_STANDARD */ {
+ if (called)
+ hf_pc = &hf_sccp_called_chinese_pc;
+ else
+ hf_pc = &hf_sccp_calling_chinese_pc;
+ }
+
+ /* create the DPC tree; modified from that in packet-mtp3.c */
+ dpc = tvb_get_ntoh24(tvb, offset);
+ snprintf(pc, sizeof(pc), "%d-%d-%d", (dpc & ANSI_NETWORK_MASK),
+ ((dpc & ANSI_CLUSTER_MASK) >> 8),
+ ((dpc & ANSI_MEMBER_MASK) >> 16));
+
+ call_pc_item = proto_tree_add_string_format(call_tree, *hf_pc,
+ tvb, offset, ANSI_PC_LENGTH,
+ pc, "PC (%s)", pc);
+
+ call_pc_tree = proto_item_add_subtree(call_pc_item,
+ called ? ett_sccp_called_pc
+ : ett_sccp_calling_pc);
+
+ proto_tree_add_uint(call_pc_tree, called ? hf_sccp_called_pc_member
+ : hf_sccp_calling_pc_member,
+ tvb, offset, ANSI_NCM_LENGTH, dpc);
+ offset += ANSI_NCM_LENGTH;
+ proto_tree_add_uint(call_pc_tree, called ? hf_sccp_called_pc_cluster
+ : hf_sccp_calling_pc_cluster,
+ tvb, offset, ANSI_NCM_LENGTH, dpc);
+ offset += ANSI_NCM_LENGTH;
+ proto_tree_add_uint(call_pc_tree, called ? hf_sccp_called_pc_network
+ : hf_sccp_calling_pc_network,
+ tvb, offset, ANSI_NCM_LENGTH, dpc);
+ offset += ANSI_NCM_LENGTH;
+
+ return(offset);
+}
+
+/* FUNCTION dissect_sccp_called_calling_param():
+ * Dissect the Calling or Called Party Address parameters.
+ *
+ * The boolean 'called' describes whether this function is decoding a
+ * called (TRUE) or calling (FALSE) party address. There is simply too
+ * much code in this function to have 2 copies of it (one for called, one
+ * for calling).
+ *
+ * NOTE: this function is called even when (!tree) so that we can get
+ * the SSN and subsequently call subdissectors (if and when there's a data
+ * parameter). Realistically we should put if (!tree)'s around a lot of the
+ * code, but I think that would make it unreadable--and the expense of not
+ * doing so does not appear to be very high.
+ */
+static void
+dissect_sccp_called_calling_param(tvbuff_t *tvb, proto_tree *tree,
+ guint length, gboolean called)
+{
+ proto_item *call_item = 0, *call_ai_item = 0;
+ proto_tree *call_tree = 0, *call_ai_tree = 0;
+ guint offset;
+ guint8 national = -1, routing_ind, gti, pci, ssni, ssn;
+ guint32 dpc;
+ tvbuff_t *gt_tvb;
+
+ call_item = proto_tree_add_text(tree, tvb, 0, length,
+ "%s Party address (%u byte%s)",
+ called ? "Called" : "Calling", length,
+ plurality(length, "", "s"));
+ call_tree = proto_item_add_subtree(call_item, called ? ett_sccp_called
+ : ett_sccp_calling);
+
+ call_ai_item = proto_tree_add_text(call_tree, tvb, 0,
+ ADDRESS_INDICATOR_LENGTH,
+ "Address Indicator");
+ call_ai_tree = proto_item_add_subtree(call_ai_item, called ? ett_sccp_called_ai
+ : ett_sccp_calling_ai);
+
+ if (mtp3_standard == ANSI_STANDARD)
+ {
+ national = tvb_get_guint8(tvb, 0) & ANSI_NATIONAL_MASK;
+ proto_tree_add_uint(call_ai_tree, called ? hf_sccp_called_national_indicator
+ : hf_sccp_calling_national_indicator,
+ tvb, 0, ADDRESS_INDICATOR_LENGTH, national);
+ }
+
+ routing_ind = tvb_get_guint8(tvb, 0) & ROUTING_INDICATOR_MASK;
+ proto_tree_add_uint(call_ai_tree, called ? hf_sccp_called_routing_indicator
+ : hf_sccp_calling_routing_indicator,
+ tvb, 0, ADDRESS_INDICATOR_LENGTH, routing_ind);
+
+ gti = tvb_get_guint8(tvb, 0) & GTI_MASK;
+
+ if (mtp3_standard == ITU_STANDARD ||
+ mtp3_standard == CHINESE_ITU_STANDARD ||
+ national == 0) {
+
+ proto_tree_add_uint(call_ai_tree, called ? hf_sccp_called_itu_global_title_indicator
+ : hf_sccp_called_itu_global_title_indicator,
+ tvb, 0, ADDRESS_INDICATOR_LENGTH, gti);
+
+ ssni = tvb_get_guint8(tvb, 0) & ITU_SSN_INDICATOR_MASK;
+ proto_tree_add_uint(call_ai_tree, called ? hf_sccp_called_itu_ssn_indicator
+ : hf_sccp_calling_itu_ssn_indicator,
+ tvb, 0, ADDRESS_INDICATOR_LENGTH, ssni);
+
+ pci = tvb_get_guint8(tvb, 0) & ITU_PC_INDICATOR_MASK;
+ proto_tree_add_uint(call_ai_tree, called ? hf_sccp_called_itu_point_code_indicator
+ : hf_sccp_calling_itu_point_code_indicator,
+ tvb, 0, ADDRESS_INDICATOR_LENGTH, pci);
+
+ offset = ADDRESS_INDICATOR_LENGTH;
+
+ /* Dissect PC (if present) */
+ if (pci) {
+ if (mtp3_standard == ITU_STANDARD)
+ {
+
+ dpc = tvb_get_letohs(tvb, offset) & ITU_PC_MASK;
+ proto_tree_add_uint(call_tree, called ? hf_sccp_called_itu_pc
+ : hf_sccp_calling_itu_pc,
+ tvb, offset, ITU_PC_LENGTH, dpc);
+ offset += ITU_PC_LENGTH;
+
+ } else /* CHINESE_ITU_STANDARD */ {
+
+ offset = dissect_sccp_3byte_pc(tvb, call_tree, offset, called);
+
+ }
+ }
+
+ /* Dissect SSN (if present) */
+ if (ssni) {
+ ssn = tvb_get_guint8(tvb, offset);
+ if (called) {
+ called_ssn = ssn;
+ }
+ else {
+ calling_ssn = ssn;
+ }
+
+ proto_tree_add_uint(call_tree, called ? hf_sccp_called_ssn
+ : hf_sccp_calling_ssn,
+ tvb, offset, ADDRESS_SSN_LENGTH, ssn);
+ proto_tree_add_uint_hidden(call_tree, hf_sccp_ssn, tvb, offset,
+ ADDRESS_SSN_LENGTH, ssn);
+ offset += ADDRESS_SSN_LENGTH;
+ }
+
+ if (!tree)
+ return; /* got SSN, that's all we need here... */
+
+ /* Dissect GT (if present) */
+ if (gti != AI_GTI_NO_GT) {
+ if (length < offset)
+ return;
+ gt_tvb = tvb_new_subset(tvb, offset, (length - offset),
+ (length - offset));
+ dissect_sccp_global_title(gt_tvb, call_tree, (length - offset), gti,
+ called);
+ }
+
+ } else if (mtp3_standard == ANSI_STANDARD) {
+
+ proto_tree_add_uint(call_ai_tree, called ? hf_sccp_called_ansi_global_title_indicator
+ : hf_sccp_calling_ansi_global_title_indicator,
+ tvb, 0, ADDRESS_INDICATOR_LENGTH, gti);
+
+ pci = tvb_get_guint8(tvb, 0) & ANSI_PC_INDICATOR_MASK;
+ proto_tree_add_uint(call_ai_tree, called ? hf_sccp_called_ansi_point_code_indicator
+ : hf_sccp_calling_ansi_point_code_indicator,
+ tvb, 0, ADDRESS_INDICATOR_LENGTH, pci);
+
+ ssni = tvb_get_guint8(tvb, 0) & ANSI_SSN_INDICATOR_MASK;
+ proto_tree_add_uint(call_ai_tree, called ? hf_sccp_called_ansi_ssn_indicator
+ : hf_sccp_calling_ansi_ssn_indicator,
+ tvb, 0, ADDRESS_INDICATOR_LENGTH, ssni);
+
+ offset = ADDRESS_INDICATOR_LENGTH;
+
+ /* Dissect SSN (if present) */
+ if (ssni) {
+ ssn = tvb_get_guint8(tvb, offset);
+ if (called) {
+ called_ssn = ssn;
+ }
+ else {
+ calling_ssn = ssn;
+ }
+
+ proto_tree_add_uint(call_tree, called ? hf_sccp_called_ssn
+ : hf_sccp_calling_ssn,
+ tvb, offset, ADDRESS_SSN_LENGTH, ssn);
+ proto_tree_add_uint_hidden(call_tree, hf_sccp_ssn, tvb, offset,
+ ADDRESS_SSN_LENGTH, ssn);
+ offset += ADDRESS_SSN_LENGTH;
+ }
+
+ if (!tree)
+ return; /* got SSN, that's all we need here... */
+
+ /* Dissect PC (if present) */
+ if (pci) {
+ offset = dissect_sccp_3byte_pc(tvb, call_tree, offset, called);
+ }
+
+ /* Dissect GT (if present) */
+ if (gti != AI_GTI_NO_GT) {
+ if (length < offset)
+ return;
+ gt_tvb = tvb_new_subset(tvb, offset, (length - offset),
+ (length - offset));
+ dissect_sccp_global_title(gt_tvb, call_tree, (length - offset), gti,
+ called);
+ }
+
+ }
+
+}
+
+static void
+dissect_sccp_called_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ dissect_sccp_called_calling_param(tvb, tree, length, TRUE);
+}
+
+static void
+dissect_sccp_calling_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ dissect_sccp_called_calling_param(tvb, tree, length, FALSE);
+}
+
+static void
+dissect_sccp_class_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 class, handling;
+
+ class = tvb_get_guint8(tvb, 0) & CLASS_CLASS_MASK;
+ handling = tvb_get_guint8(tvb, 0) & CLASS_SPARE_HANDLING_MASK;
+
+ proto_tree_add_uint(tree, hf_sccp_class, tvb, 0, length, class);
+
+ if (class == 0 || class == 1)
+ proto_tree_add_uint(tree, hf_sccp_handling, tvb, 0, length, handling);
+}
+
+static void
+dissect_sccp_segmenting_reassembling_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 more;
+
+ more = tvb_get_guint8(tvb, 0) & SEGMENTING_REASSEMBLING_MASK;
+ proto_tree_add_uint(tree, hf_sccp_more, tvb, 0, length, more);
+}
+
+static void
+dissect_sccp_receive_sequence_number_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 rsn;
+
+ rsn = tvb_get_guint8(tvb, 0) >> 1;
+ proto_tree_add_uint(tree, hf_sccp_rsn, tvb, 0, length, rsn);
+}
+
+static void
+dissect_sccp_sequencing_segmenting_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 rsn, ssn, more;
+ proto_item *param_item;
+ proto_tree *param_tree;
+
+ ssn = tvb_get_guint8(tvb, 0) >> 1;
+ rsn = tvb_get_guint8(tvb, SEQUENCING_SEGMENTING_SSN_LENGTH) >> 1;
+ more = tvb_get_guint8(tvb, SEQUENCING_SEGMENTING_SSN_LENGTH) & SEQUENCING_SEGMENTING_MORE_MASK;
+
+ param_item = proto_tree_add_text(tree, tvb, 0, length,
+ val_to_str(PARAMETER_SEQUENCING_SEGMENTING,
+ sccp_parameter_values, "Unknown"));
+ param_tree = proto_item_add_subtree(param_item,
+ ett_sccp_sequencing_segmenting);
+
+ proto_tree_add_uint(param_tree, hf_sccp_sequencing_segmenting_ssn, tvb, 0,
+ SEQUENCING_SEGMENTING_SSN_LENGTH, ssn);
+ proto_tree_add_uint(param_tree, hf_sccp_sequencing_segmenting_rsn, tvb,
+ SEQUENCING_SEGMENTING_SSN_LENGTH,
+ SEQUENCING_SEGMENTING_RSN_LENGTH, rsn);
+ proto_tree_add_uint(param_tree, hf_sccp_sequencing_segmenting_more, tvb,
+ SEQUENCING_SEGMENTING_SSN_LENGTH,
+ SEQUENCING_SEGMENTING_RSN_LENGTH, more);
+}
+
+static void
+dissect_sccp_credit_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 credit;
+
+ credit = tvb_get_guint8(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_credit, tvb, 0, length, credit);
+}
+
+static void
+dissect_sccp_release_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 cause;
+
+ cause = tvb_get_guint8(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_release_cause, tvb, 0, length, cause);
+}
+
+static void
+dissect_sccp_return_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 cause;
+
+ cause = tvb_get_guint8(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_return_cause, tvb, 0, length, cause);
+}
+
+static void
+dissect_sccp_reset_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 cause;
+
+ cause = tvb_get_guint8(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_reset_cause, tvb, 0, length, cause);
+}
+
+static void
+dissect_sccp_error_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 cause;
+
+ cause = tvb_get_guint8(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_error_cause, tvb, 0, length, cause);
+}
+
+static void
+dissect_sccp_refusal_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 cause;
+
+ cause = tvb_get_guint8(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_refusal_cause, tvb, 0, length, cause);
+}
+
+/* This function is used for both data and long data (ITU only) parameters */
+static void
+dissect_sccp_data_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+ /* Try subdissectors (if we found a valid SSN on the current message) */
+ if ((called_ssn != INVALID_SSN &&
+ dissector_try_port(sccp_ssn_dissector_table, called_ssn, tvb, pinfo,
+ tree)) ||
+ (calling_ssn != INVALID_SSN &&
+ dissector_try_port(sccp_ssn_dissector_table, calling_ssn, tvb, pinfo,
+ tree)))
+ return;
+
+ /* try heuristic subdissector list to see if there are any takers */
+ if (dissector_try_heuristic(heur_subdissector_list, tvb, pinfo, tree))
+ {
+ return;
+ }
+
+ /* No sub-dissection occured, treat it as raw data */
+ call_dissector(data_handle, tvb, pinfo, tree);
+}
+
+static void
+dissect_sccp_segmentation_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 first, class, remaining;
+ guint32 slr;
+ proto_item *param_item;
+ proto_tree *param_tree;
+
+ first = tvb_get_guint8(tvb, 0) & SEGMENTATION_FIRST_SEGMENT_MASK;
+ class = tvb_get_guint8(tvb, 0) & SEGMENTATION_CLASS_MASK;
+ remaining = tvb_get_guint8(tvb, 0) & SEGMENTATION_REMAINING_MASK;
+
+ slr = tvb_get_letoh24(tvb, 1);
+
+ param_item = proto_tree_add_text(tree, tvb, 0, length,
+ val_to_str(PARAMETER_SEGMENTATION,
+ sccp_parameter_values, "Unknown"));
+ param_tree = proto_item_add_subtree(param_item, ett_sccp_segmentation);
+
+ proto_tree_add_uint(param_tree, hf_sccp_segmentation_first, tvb, 0, length,
+ first);
+ proto_tree_add_uint(param_tree, hf_sccp_segmentation_class, tvb, 0, length,
+ class);
+ proto_tree_add_uint(param_tree, hf_sccp_segmentation_remaining, tvb, 0,
+ length, remaining);
+ proto_tree_add_uint(param_tree, hf_sccp_segmentation_slr, tvb, 1, length,
+ slr);
+}
+
+static void
+dissect_sccp_hop_counter_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 hops;
+
+ hops = tvb_get_guint8(tvb, 0);
+ proto_tree_add_uint(tree, hf_sccp_hop_counter, tvb, 0, length, hops);
+}
+
+static void
+dissect_sccp_importance_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 importance;
+
+ importance = tvb_get_guint8(tvb, 0) & IMPORTANCE_IMPORTANCE_MASK;
+ proto_tree_add_uint(tree, hf_sccp_importance, tvb, 0, length, importance);
+}
+
+static void
+dissect_sccp_isni_param(tvbuff_t *tvb, proto_tree *tree, guint length)
+{
+ guint8 mi, iri, ti, network, netspec;
+ guint offset = 0;
+ proto_item *param_item;
+ proto_tree *param_tree;
+
+ /* Create a subtree for ISNI Routing Control */
+ param_item = proto_tree_add_text(tree, tvb, offset, ANSI_ISNI_ROUTING_CONTROL_LENGTH,
+ "ISNI Routing Control");
+ param_tree = proto_item_add_subtree(param_item,
+ ett_sccp_ansi_isni_routing_control);
+
+ mi = tvb_get_guint8(tvb, offset) & ANSI_ISNI_MI_MASK;
+ proto_tree_add_uint(param_tree, hf_sccp_ansi_isni_mi, tvb, offset,
+ ANSI_ISNI_ROUTING_CONTROL_LENGTH, mi);
+
+ iri = tvb_get_guint8(tvb, offset) & ANSI_ISNI_IRI_MASK;
+ proto_tree_add_uint(param_tree, hf_sccp_ansi_isni_iri, tvb, offset,
+ ANSI_ISNI_ROUTING_CONTROL_LENGTH, iri);
+
+ ti = tvb_get_guint8(tvb, offset) & ANSI_ISNI_TI_MASK;
+ proto_tree_add_uint(param_tree, hf_sccp_ansi_isni_ti, tvb, offset,
+ ANSI_ISNI_ROUTING_CONTROL_LENGTH, ti);
+
+ offset += ANSI_ISNI_ROUTING_CONTROL_LENGTH;
+
+ if ((ti >> ANSI_ISNI_TI_SHIFT) == ANSI_ISNI_TYPE_1) {
+ netspec = tvb_get_guint8(tvb, offset) & ANSI_ISNI_NETSPEC_MASK;
+ proto_tree_add_uint(param_tree, hf_sccp_ansi_isni_netspec, tvb, offset,
+ ANSI_ISNI_ROUTING_CONTROL_LENGTH, ti);
+ offset += ANSI_ISNI_ROUTING_CONTROL_LENGTH;
+ }
+
+ while (offset < length) {
+
+ network = tvb_get_guint8(tvb, offset);
+ proto_tree_add_text(tree, tvb, offset, ANSI_NCM_LENGTH,
+ "Network ID network: %d", network);
+ offset++;
+
+ network = tvb_get_guint8(tvb, offset);
+ proto_tree_add_text(tree, tvb, offset, ANSI_NCM_LENGTH,
+ "Network ID cluster: %d", network);
+ offset++;
+ }
+
+}
+
+/* FUNCTION dissect_sccp_parameter():
+ * Dissect a parameter given its type, offset into tvb, and length.
+ */
+static guint16
+dissect_sccp_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *sccp_tree,
+ proto_tree *tree, guint8 parameter_type, guint16 offset,
+ guint16 parameter_length)
+{
+ tvbuff_t *parameter_tvb;
+
+ switch (parameter_type) {
+ case PARAMETER_CALLED_PARTY_ADDRESS:
+ case PARAMETER_CALLING_PARTY_ADDRESS:
+ case PARAMETER_DATA:
+ case PARAMETER_LONG_DATA:
+ /* These parameters must be dissected even if !sccp_tree (so that
+ * subdissectors can be called).
+ */
+ break;
+
+ default:
+ if (!sccp_tree)
+ return(parameter_length);
+
+ }
+
+ parameter_tvb = tvb_new_subset(tvb, offset, parameter_length, parameter_length);
+
+ switch (parameter_type) {
+
+ case PARAMETER_END_OF_OPTIONAL_PARAMETERS:
+ proto_tree_add_text(sccp_tree, tvb, offset, parameter_length,
+ "End of Optional");
+ break;
+
+ case PARAMETER_DESTINATION_LOCAL_REFERENCE:
+ dissect_sccp_dlr_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_SOURCE_LOCAL_REFERENCE:
+ dissect_sccp_slr_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_CALLED_PARTY_ADDRESS:
+ dissect_sccp_called_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_CALLING_PARTY_ADDRESS:
+ dissect_sccp_calling_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_CLASS:
+ dissect_sccp_class_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_SEGMENTING_REASSEMBLING:
+ dissect_sccp_segmenting_reassembling_param(parameter_tvb, sccp_tree,
+ parameter_length);
+ break;
+
+ case PARAMETER_RECEIVE_SEQUENCE_NUMBER:
+ dissect_sccp_receive_sequence_number_param(parameter_tvb, sccp_tree,
+ parameter_length);
+ break;
+
+ case PARAMETER_SEQUENCING_SEGMENTING:
+ dissect_sccp_sequencing_segmenting_param(parameter_tvb, sccp_tree,
+ parameter_length);
+ break;
+
+ case PARAMETER_CREDIT:
+ dissect_sccp_credit_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_RELEASE_CAUSE:
+ dissect_sccp_release_cause_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_RETURN_CAUSE:
+ dissect_sccp_return_cause_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_RESET_CAUSE:
+ dissect_sccp_reset_cause_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_ERROR_CAUSE:
+ dissect_sccp_error_cause_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_REFUSAL_CAUSE:
+ dissect_sccp_refusal_cause_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_DATA:
+ dissect_sccp_data_param(parameter_tvb, pinfo, tree);
+
+ /* TODO? Re-adjust length of SCCP item since it may be sub-dissected */
+ /* sccp_length = proto_item_get_len(sccp_item);
+ * sccp_length -= parameter_length;
+ * proto_item_set_len(sccp_item, sccp_length);
+ */
+ break;
+
+ case PARAMETER_SEGMENTATION:
+ dissect_sccp_segmentation_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_HOP_COUNTER:
+ dissect_sccp_hop_counter_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ case PARAMETER_IMPORTANCE:
+ if (mtp3_standard != ANSI_STANDARD)
+ dissect_sccp_importance_param(parameter_tvb, sccp_tree, parameter_length);
+ else
+ dissect_sccp_unknown_param(parameter_tvb, sccp_tree, parameter_type,
+ parameter_length);
+ break;
+
+ case PARAMETER_LONG_DATA:
+ if (mtp3_standard != ANSI_STANDARD)
+ dissect_sccp_data_param(parameter_tvb, pinfo, tree);
+ else
+ dissect_sccp_unknown_param(parameter_tvb, sccp_tree, parameter_type,
+ parameter_length);
+ break;
+
+ case PARAMETER_ISNI:
+ if (mtp3_standard != ANSI_STANDARD)
+ dissect_sccp_unknown_param(parameter_tvb, sccp_tree, parameter_type,
+ parameter_length);
+ else
+ dissect_sccp_isni_param(parameter_tvb, sccp_tree, parameter_length);
+ break;
+
+ default:
+ dissect_sccp_unknown_param(parameter_tvb, sccp_tree, parameter_type,
+ parameter_length);
+ break;
+ }
+
+ return(parameter_length);
+}
+
+/* FUNCTION dissect_sccp_variable_parameter():
+ * Dissect a variable parameter given its type and offset into tvb. Length
+ * of the parameter is gotten from tvb[0].
+ * Length returned is sum of (length + parameter).
+ */
+static guint16
+dissect_sccp_variable_parameter(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *sccp_tree, proto_tree *tree,
+ guint8 parameter_type, guint16 offset)
+{
+ guint16 parameter_length;
+ guint8 length_length;
+
+ if (parameter_type != PARAMETER_LONG_DATA)
+ {
+ parameter_length = tvb_get_guint8(tvb, offset);
+ length_length = PARAMETER_LENGTH_LENGTH;
+ }
+ else
+ {
+ /* Long data parameter has 16 bit length */
+ parameter_length = tvb_get_letohs(tvb, offset);
+ length_length = PARAMETER_LONG_DATA_LENGTH_LENGTH;
+ }
+
+ if (sccp_tree &&
+ sccp_show_length)
+ {
+ proto_tree_add_text(sccp_tree, tvb, offset, length_length,
+ "%s length: %d",
+ val_to_str(parameter_type, sccp_parameter_values,
+ "Unknown"),
+ parameter_length);
+ }
+
+ offset += length_length;
+
+ dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree, parameter_type, offset,
+ parameter_length);
+
+ return(parameter_length + length_length);
+}
+
+/* FUNCTION dissect_sccp_optional_parameters():
+ * Dissect all the optional parameters given the start of the optional
+ * parameters into tvb. Parameter types and lengths are read from tvb.
+ */
+static void
+dissect_sccp_optional_parameters(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *sccp_tree, proto_tree *tree,
+ guint16 offset)
+{
+ guint8 parameter_type;
+
+ while ((parameter_type = tvb_get_guint8(tvb, offset)) !=
+ PARAMETER_END_OF_OPTIONAL_PARAMETERS) {
+
+ offset += PARAMETER_TYPE_LENGTH;
+ offset += dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ parameter_type, offset);
+ }
+
+ /* Process end of optional parameters */
+ dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree, parameter_type, offset,
+ END_OF_OPTIONAL_PARAMETERS_LENGTH);
+
+}
+
+
+static void
+dissect_sccp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *sccp_tree,
+ proto_tree *tree)
+{
+ guint8 message_type;
+ guint16 variable_pointer1 = 0, variable_pointer2 = 0, variable_pointer3 = 0;
+ guint16 optional_pointer = 0;
+ guint16 offset = 0;
+
+/* Macro for getting pointer to mandatory variable parameters */
+#define VARIABLE_POINTER(var, hf_var, ptr_size) \
+ if (ptr_size == POINTER_LENGTH) \
+ var = tvb_get_guint8(tvb, offset); \
+ else \
+ var = tvb_get_letohs(tvb, offset); \
+ proto_tree_add_uint(sccp_tree, hf_var, tvb, \
+ offset, ptr_size, var); \
+ var += offset; \
+ if (ptr_size == POINTER_LENGTH_LONG) \
+ var += 1; \
+ offset += ptr_size;
+
+/* Macro for getting pointer to optional parameters */
+#define OPTIONAL_POINTER(ptr_size) \
+ if (ptr_size == POINTER_LENGTH) \
+ optional_pointer = tvb_get_guint8(tvb, offset); \
+ else \
+ optional_pointer = tvb_get_letohs(tvb, offset); \
+ proto_tree_add_uint(sccp_tree, hf_sccp_optional_pointer, tvb, \
+ offset, ptr_size, optional_pointer); \
+ optional_pointer += offset; \
+ if (ptr_size == POINTER_LENGTH_LONG) \
+ optional_pointer += 1; \
+ offset += ptr_size;
+
+
+ /* Extract the message type; all other processing is based on this */
+ message_type = tvb_get_guint8(tvb, MESSAGE_TYPE_OFFSET);
+ offset = MESSAGE_TYPE_LENGTH;
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+ val_to_str(message_type, sccp_message_type_acro_values, "Unknown"));
+
+ if (sccp_tree) {
+ /* add the message type to the protocol tree */
+ proto_tree_add_uint(sccp_tree, hf_sccp_message_type, tvb,
+ MESSAGE_TYPE_OFFSET, MESSAGE_TYPE_LENGTH, message_type);
+
+ };
+
+ /* Starting a new message dissection; clear the global SSN values */
+ called_ssn = INVALID_SSN;
+ calling_ssn = INVALID_SSN;
+
+ switch(message_type) {
+ case MESSAGE_TYPE_CR:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SOURCE_LOCAL_REFERENCE,
+ offset, SOURCE_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CLASS, offset,
+ PROTOCOL_CLASS_LENGTH);
+
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH)
+ OPTIONAL_POINTER(POINTER_LENGTH)
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLED_PARTY_ADDRESS,
+ variable_pointer1);
+ break;
+
+ case MESSAGE_TYPE_CC:
+ /* TODO: connection has been established; theoretically we could keep
+ * keep track of the SLR/DLR with the called/calling from the CR and
+ * track the connection (e.g., on subsequent messages regarding this
+ * SLR we could set the global vars "call*_ssn" so data could get
+ * sub-dissected).
+ */
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SOURCE_LOCAL_REFERENCE,
+ offset, SOURCE_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CLASS, offset,
+ PROTOCOL_CLASS_LENGTH);
+ OPTIONAL_POINTER(POINTER_LENGTH)
+ break;
+
+ case MESSAGE_TYPE_CREF:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_REFUSAL_CAUSE, offset,
+ REFUSAL_CAUSE_LENGTH);
+ OPTIONAL_POINTER(POINTER_LENGTH)
+ break;
+
+ case MESSAGE_TYPE_RLSD:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SOURCE_LOCAL_REFERENCE,
+ offset, SOURCE_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_RELEASE_CAUSE, offset,
+ RELEASE_CAUSE_LENGTH);
+
+ OPTIONAL_POINTER(POINTER_LENGTH)
+ break;
+
+ case MESSAGE_TYPE_RLC:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SOURCE_LOCAL_REFERENCE,
+ offset, SOURCE_LOCAL_REFERENCE_LENGTH);
+ break;
+
+ case MESSAGE_TYPE_DT1:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SEGMENTING_REASSEMBLING,
+ offset, SEGMENTING_REASSEMBLING_LENGTH);
+
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH)
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree, PARAMETER_DATA,
+ variable_pointer1);
+ break;
+
+ case MESSAGE_TYPE_DT2:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SEQUENCING_SEGMENTING, offset,
+ SEQUENCING_SEGMENTING_LENGTH);
+ break;
+
+ case MESSAGE_TYPE_AK:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_RECEIVE_SEQUENCE_NUMBER,
+ offset, RECEIVE_SEQUENCE_NUMBER_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CREDIT, offset, CREDIT_LENGTH);
+ break;
+
+ case MESSAGE_TYPE_UDT:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CLASS, offset,
+ PROTOCOL_CLASS_LENGTH);
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH)
+ VARIABLE_POINTER(variable_pointer2, hf_sccp_variable_pointer2, POINTER_LENGTH)
+ VARIABLE_POINTER(variable_pointer3, hf_sccp_variable_pointer3, POINTER_LENGTH)
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLED_PARTY_ADDRESS,
+ variable_pointer1);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLING_PARTY_ADDRESS,
+ variable_pointer2);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree, PARAMETER_DATA,
+ variable_pointer3);
+ break;
+
+ case MESSAGE_TYPE_UDTS:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_RETURN_CAUSE, offset,
+ RETURN_CAUSE_LENGTH);
+
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH)
+ VARIABLE_POINTER(variable_pointer2, hf_sccp_variable_pointer2, POINTER_LENGTH)
+ VARIABLE_POINTER(variable_pointer3, hf_sccp_variable_pointer3, POINTER_LENGTH)
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLED_PARTY_ADDRESS,
+ variable_pointer1);
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLING_PARTY_ADDRESS,
+ variable_pointer2);
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree, PARAMETER_DATA,
+ variable_pointer3);
+ break;
+
+ case MESSAGE_TYPE_ED:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH)
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree, PARAMETER_DATA,
+ variable_pointer1);
+ break;
+
+ case MESSAGE_TYPE_EA:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ break;
+
+ case MESSAGE_TYPE_RSR:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SOURCE_LOCAL_REFERENCE,
+ offset, SOURCE_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_RESET_CAUSE, offset,
+ RESET_CAUSE_LENGTH);
+ break;
+
+ case MESSAGE_TYPE_RSC:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SOURCE_LOCAL_REFERENCE,
+ offset, SOURCE_LOCAL_REFERENCE_LENGTH);
+ break;
+
+ case MESSAGE_TYPE_ERR:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_ERROR_CAUSE, offset,
+ ERROR_CAUSE_LENGTH);
+ break;
+
+ case MESSAGE_TYPE_IT:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_DESTINATION_LOCAL_REFERENCE,
+ offset,
+ DESTINATION_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SOURCE_LOCAL_REFERENCE,
+ offset, SOURCE_LOCAL_REFERENCE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CLASS, offset,
+ PROTOCOL_CLASS_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_SEQUENCING_SEGMENTING,
+ offset, SEQUENCING_SEGMENTING_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CREDIT, offset, CREDIT_LENGTH);
+ break;
+
+ case MESSAGE_TYPE_XUDT:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CLASS, offset,
+ PROTOCOL_CLASS_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_HOP_COUNTER, offset,
+ HOP_COUNTER_LENGTH);
+
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH)
+ VARIABLE_POINTER(variable_pointer2, hf_sccp_variable_pointer2, POINTER_LENGTH)
+ VARIABLE_POINTER(variable_pointer3, hf_sccp_variable_pointer3, POINTER_LENGTH)
+ OPTIONAL_POINTER(POINTER_LENGTH)
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLED_PARTY_ADDRESS,
+ variable_pointer1);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLING_PARTY_ADDRESS,
+ variable_pointer2);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree, PARAMETER_DATA,
+ variable_pointer3);
+ break;
+
+ case MESSAGE_TYPE_XUDTS:
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_RETURN_CAUSE, offset,
+ RETURN_CAUSE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_HOP_COUNTER, offset,
+ HOP_COUNTER_LENGTH);
+
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH)
+ VARIABLE_POINTER(variable_pointer2, hf_sccp_variable_pointer2, POINTER_LENGTH)
+ VARIABLE_POINTER(variable_pointer3, hf_sccp_variable_pointer3, POINTER_LENGTH)
+ OPTIONAL_POINTER(POINTER_LENGTH)
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLED_PARTY_ADDRESS,
+ variable_pointer1);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLING_PARTY_ADDRESS,
+ variable_pointer2);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree, PARAMETER_DATA,
+ variable_pointer3);
+ break;
+
+ case MESSAGE_TYPE_LUDT:
+ if (mtp3_standard != ANSI_STANDARD)
+ {
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CLASS, offset,
+ PROTOCOL_CLASS_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_HOP_COUNTER, offset,
+ HOP_COUNTER_LENGTH);
+
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH_LONG)
+ VARIABLE_POINTER(variable_pointer2, hf_sccp_variable_pointer2, POINTER_LENGTH_LONG)
+ VARIABLE_POINTER(variable_pointer3, hf_sccp_variable_pointer3, POINTER_LENGTH_LONG)
+ OPTIONAL_POINTER(POINTER_LENGTH_LONG)
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLED_PARTY_ADDRESS,
+ variable_pointer1);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLING_PARTY_ADDRESS,
+ variable_pointer2);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_LONG_DATA, variable_pointer3);
+ } else
+ dissect_sccp_unknown_message(tvb, sccp_tree);
+ break;
+
+ case MESSAGE_TYPE_LUDTS:
+ if (mtp3_standard != ANSI_STANDARD)
+ {
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_RETURN_CAUSE, offset,
+ RETURN_CAUSE_LENGTH);
+ offset += dissect_sccp_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_HOP_COUNTER, offset,
+ HOP_COUNTER_LENGTH);
+
+ VARIABLE_POINTER(variable_pointer1, hf_sccp_variable_pointer1, POINTER_LENGTH_LONG)
+ VARIABLE_POINTER(variable_pointer2, hf_sccp_variable_pointer2, POINTER_LENGTH_LONG)
+ VARIABLE_POINTER(variable_pointer3, hf_sccp_variable_pointer3, POINTER_LENGTH_LONG)
+ OPTIONAL_POINTER(POINTER_LENGTH_LONG)
+
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLED_PARTY_ADDRESS,
+ variable_pointer1);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_CALLING_PARTY_ADDRESS,
+ variable_pointer2);
+ dissect_sccp_variable_parameter(tvb, pinfo, sccp_tree, tree,
+ PARAMETER_LONG_DATA, variable_pointer3);
+ } else
+ dissect_sccp_unknown_message(tvb, sccp_tree);
+ break;
+
+ default:
+ dissect_sccp_unknown_message(tvb, sccp_tree);
+ }
+
+ if (optional_pointer)
+ dissect_sccp_optional_parameters(tvb, pinfo, sccp_tree, tree,
+ optional_pointer);
+
+}
+
+static void
+dissect_sccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *sccp_item;
+ proto_tree *sccp_tree = NULL;
+ const mtp3_addr_pc_t *mtp3_addr_p;
+
+ /* Make entry in the Protocol column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ switch(mtp3_standard) {
+ case ITU_STANDARD:
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCCP (Int. ITU)");
+ break;
+ case ANSI_STANDARD:
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCCP (ANSI)");
+ break;
+ case CHINESE_ITU_STANDARD:
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCCP (Chin. ITU)");
+ break;
+ };
+
+ /* In the interest of speed, if "tree" is NULL, don't do any work not
+ necessary to generate protocol tree items. */
+ if (tree) {
+ /* create the sccp protocol tree */
+ sccp_item = proto_tree_add_item(tree, proto_sccp, tvb, 0, -1, FALSE);
+ sccp_tree = proto_item_add_subtree(sccp_item, ett_sccp);
+ }
+
+ /* Set whether message is UPLINK, DOWNLINK, or of UNKNOWN direction */
+
+ if (pinfo->net_src.type == AT_SS7PC)
+ {
+ /*
+ * XXX - we assume that the "data" pointers of the source and destination
+ * addresses are set to point to "mtp3_addr_pc_t" structures, so that
+ * we can safely cast them.
+ */
+ mtp3_addr_p = (const mtp3_addr_pc_t *)pinfo->net_src.data;
+
+ if (sccp_source_pc_global == mtp3_addr_p->pc)
+ {
+ pinfo->p2p_dir = P2P_DIR_SENT;
+ }
+ else
+ {
+ /* assuming if net_src was SS7 PC then net_dst will be too */
+ mtp3_addr_p = (const mtp3_addr_pc_t *)pinfo->net_dst.data;
+
+ if (sccp_source_pc_global == mtp3_addr_p->pc)
+ {
+ pinfo->p2p_dir = P2P_DIR_RECV;
+ }
+ else
+ {
+ pinfo->p2p_dir = P2P_DIR_UNKNOWN;
+ }
+ }
+ }
+
+ /* dissect the message */
+ dissect_sccp_message(tvb, pinfo, sccp_tree, tree);
+}
+
+/* Register the protocol with Ethereal */
+void
+proto_register_sccp(void)
+{
+ /* Setup list of header fields */
+ static hf_register_info hf[] = {
+ { &hf_sccp_message_type,
+ { "Message Type", "sccp.message_type",
+ FT_UINT8, BASE_HEX, VALS(sccp_message_type_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_variable_pointer1,
+ { "Pointer to first Mandatory Variable parameter", "sccp.variable_pointer1",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_variable_pointer2,
+ { "Pointer to second Mandatory Variable parameter", "sccp.variable_pointer2",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_variable_pointer3,
+ { "Pointer to third Mandatory Variable parameter", "sccp.variable_pointer3",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_optional_pointer,
+ { "Pointer to Optional parameter", "sccp.optional_pointer",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_ssn,
+ { "Called or Calling SubSystem Number", "sccp.ssn",
+ FT_UINT8, BASE_DEC, VALS(sccp_ssn_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_gt_digits,
+ { "Called or Calling GT Digits",
+ "sccp.digits",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_sccp_called_national_indicator,
+ { "National Indicator", "sccp.called.ni",
+ FT_UINT8, BASE_HEX, VALS(sccp_national_indicator_values), ANSI_NATIONAL_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_routing_indicator,
+ { "Routing Indicator", "sccp.called.ri",
+ FT_UINT8, BASE_HEX, VALS(sccp_routing_indicator_values), ROUTING_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_itu_global_title_indicator,
+ { "Global Title Indicator", "sccp.called.gti",
+ FT_UINT8, BASE_HEX, VALS(sccp_itu_global_title_indicator_values), GTI_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_ansi_global_title_indicator,
+ { "Global Title Indicator", "sccp.called.gti",
+ FT_UINT8, BASE_HEX, VALS(sccp_ansi_global_title_indicator_values), GTI_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_itu_ssn_indicator,
+ { "SubSystem Number Indicator", "sccp.called.ssni",
+ FT_UINT8, BASE_HEX, VALS(sccp_ai_ssni_values), ITU_SSN_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_itu_point_code_indicator,
+ { "Point Code Indicator", "sccp.called.pci",
+ FT_UINT8, BASE_HEX, VALS(sccp_ai_pci_values), ITU_PC_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_ansi_ssn_indicator,
+ { "SubSystem Number Indicator", "sccp.called.ssni",
+ FT_UINT8, BASE_HEX, VALS(sccp_ai_ssni_values), ANSI_SSN_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_ansi_point_code_indicator,
+ { "Point Code Indicator", "sccp.called.pci",
+ FT_UINT8, BASE_HEX, VALS(sccp_ai_pci_values), ANSI_PC_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_ssn,
+ { "SubSystem Number", "sccp.called.ssn",
+ FT_UINT8, BASE_DEC, VALS(sccp_ssn_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_called_itu_pc,
+ { "PC", "sccp.called.pc",
+ FT_UINT16, BASE_DEC, NULL, ITU_PC_MASK,
+ "", HFILL}},
+ { &hf_sccp_called_ansi_pc,
+ { "PC", "sccp.called.ansi_pc",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_called_chinese_pc,
+ { "PC", "sccp.called.chinese_pc",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_called_pc_network,
+ { "PC Network",
+ "sccp.called.network",
+ FT_UINT24, BASE_DEC, NULL, ANSI_NETWORK_MASK,
+ "", HFILL }},
+ { &hf_sccp_called_pc_cluster,
+ { "PC Cluster",
+ "sccp.called.cluster",
+ FT_UINT24, BASE_DEC, NULL, ANSI_CLUSTER_MASK,
+ "", HFILL }},
+ { &hf_sccp_called_pc_member,
+ { "PC Member",
+ "sccp.called.member",
+ FT_UINT24, BASE_DEC, NULL, ANSI_MEMBER_MASK,
+ "", HFILL }},
+ { &hf_sccp_called_gt_nai,
+ { "Nature of Address Indicator",
+ "sccp.called.nai",
+ FT_UINT8, BASE_HEX, VALS(sccp_nai_values), GT_NAI_MASK,
+ "", HFILL }},
+ { &hf_sccp_called_gt_oe,
+ { "Odd/Even Indicator",
+ "sccp.called.oe",
+ FT_UINT8, BASE_HEX, VALS(sccp_oe_values), GT_OE_MASK,
+ "", HFILL }},
+ { &hf_sccp_called_gt_tt,
+ { "Translation Type",
+ "sccp.called.tt",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL }},
+ { &hf_sccp_called_gt_np,
+ { "Numbering Plan",
+ "sccp.called.np",
+ FT_UINT8, BASE_HEX, VALS(sccp_np_values), GT_NP_MASK,
+ "", HFILL }},
+ { &hf_sccp_called_gt_es,
+ { "Encoding Scheme",
+ "sccp.called.es",
+ FT_UINT8, BASE_HEX, VALS(sccp_es_values), GT_ES_MASK,
+ "", HFILL }},
+ { &hf_sccp_called_gt_digits,
+ { "GT Digits",
+ "sccp.called.digits",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_sccp_calling_national_indicator,
+ { "National Indicator", "sccp.calling.ni",
+ FT_UINT8, BASE_HEX, VALS(sccp_national_indicator_values), ANSI_NATIONAL_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_routing_indicator,
+ { "Routing Indicator", "sccp.calling.ri",
+ FT_UINT8, BASE_HEX, VALS(sccp_routing_indicator_values), ROUTING_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_itu_global_title_indicator,
+ { "Global Title Indicator", "sccp.calling.gti",
+ FT_UINT8, BASE_HEX, VALS(sccp_itu_global_title_indicator_values), GTI_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_ansi_global_title_indicator,
+ { "Global Title Indicator", "sccp.calling.gti",
+ FT_UINT8, BASE_HEX, VALS(sccp_ansi_global_title_indicator_values), GTI_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_itu_ssn_indicator,
+ { "SubSystem Number Indicator", "sccp.calling.ssni",
+ FT_UINT8, BASE_HEX, VALS(sccp_ai_ssni_values), ITU_SSN_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_itu_point_code_indicator,
+ { "Point Code Indicator", "sccp.calling.pci",
+ FT_UINT8, BASE_HEX, VALS(sccp_ai_pci_values), ITU_PC_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_ansi_ssn_indicator,
+ { "SubSystem Number Indicator", "sccp.calling.ssni",
+ FT_UINT8, BASE_HEX, VALS(sccp_ai_ssni_values), ANSI_SSN_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_ansi_point_code_indicator,
+ { "Point Code Indicator", "sccp.calling.pci",
+ FT_UINT8, BASE_HEX, VALS(sccp_ai_pci_values), ANSI_PC_INDICATOR_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_ssn,
+ { "SubSystem Number", "sccp.calling.ssn",
+ FT_UINT8, BASE_DEC, VALS(sccp_ssn_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_calling_itu_pc,
+ { "PC", "sccp.calling.pc",
+ FT_UINT16, BASE_DEC, NULL, ITU_PC_MASK,
+ "", HFILL}},
+ { &hf_sccp_calling_ansi_pc,
+ { "PC", "sccp.calling.ansi_pc",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_calling_chinese_pc,
+ { "PC", "sccp.calling.chinese_pc",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_calling_pc_network,
+ { "PC Network",
+ "sccp.calling.network",
+ FT_UINT24, BASE_DEC, NULL, ANSI_NETWORK_MASK,
+ "", HFILL }},
+ { &hf_sccp_calling_pc_cluster,
+ { "PC Cluster",
+ "sccp.calling.cluster",
+ FT_UINT24, BASE_DEC, NULL, ANSI_CLUSTER_MASK,
+ "", HFILL }},
+ { &hf_sccp_calling_pc_member,
+ { "PC Member",
+ "sccp.calling.member",
+ FT_UINT24, BASE_DEC, NULL, ANSI_MEMBER_MASK,
+ "", HFILL }},
+ { &hf_sccp_calling_gt_nai,
+ { "Nature of Address Indicator",
+ "sccp.calling.nai",
+ FT_UINT8, BASE_HEX, VALS(sccp_nai_values), GT_NAI_MASK,
+ "", HFILL }},
+ { &hf_sccp_calling_gt_oe,
+ { "Odd/Even Indicator",
+ "sccp.calling.oe",
+ FT_UINT8, BASE_HEX, VALS(sccp_oe_values), GT_OE_MASK,
+ "", HFILL }},
+ { &hf_sccp_calling_gt_tt,
+ { "Translation Type",
+ "sccp.calling.tt",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL }},
+ { &hf_sccp_calling_gt_np,
+ { "Numbering Plan",
+ "sccp.calling.np",
+ FT_UINT8, BASE_HEX, VALS(sccp_np_values), GT_NP_MASK,
+ "", HFILL }},
+ { &hf_sccp_calling_gt_es,
+ { "Encoding Scheme",
+ "sccp.calling.es",
+ FT_UINT8, BASE_HEX, VALS(sccp_es_values), GT_ES_MASK,
+ "", HFILL }},
+ { &hf_sccp_calling_gt_digits,
+ { "GT Digits",
+ "sccp.calling.digits",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_sccp_dlr,
+ { "Destination Local Reference", "sccp.dlr",
+ FT_UINT24, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_slr,
+ { "Source Local Reference", "sccp.slr",
+ FT_UINT24, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_class,
+ { "Class", "sccp.class",
+ FT_UINT8, BASE_HEX, NULL, CLASS_CLASS_MASK,
+ "", HFILL}},
+ { &hf_sccp_handling,
+ { "Message handling", "sccp.handling",
+ FT_UINT8, BASE_HEX, VALS(sccp_class_handling_values), CLASS_SPARE_HANDLING_MASK,
+ "", HFILL}},
+ { &hf_sccp_more,
+ { "More data", "sccp.more",
+ FT_UINT8, BASE_HEX, VALS(sccp_segmenting_reassembling_values), SEGMENTING_REASSEMBLING_MASK,
+ "", HFILL}},
+ { &hf_sccp_rsn,
+ { "Receive Sequence Number", "sccp.rsn",
+ FT_UINT8, BASE_HEX, NULL, RSN_MASK,
+ "", HFILL}},
+ { &hf_sccp_sequencing_segmenting_ssn,
+ { "Sequencing Segmenting: Send Sequence Number", "sccp.sequencing_segmenting.ssn",
+ FT_UINT8, BASE_HEX, NULL, SEND_SEQUENCE_NUMBER_MASK,
+ "", HFILL}},
+ { &hf_sccp_sequencing_segmenting_rsn,
+ { "Sequencing Segmenting: Receive Sequence Number", "sccp.sequencing_segmenting.rsn",
+ FT_UINT8, BASE_HEX, NULL, RECEIVE_SEQUENCE_NUMBER_MASK,
+ "", HFILL}},
+ { &hf_sccp_sequencing_segmenting_more,
+ { "Sequencing Segmenting: More", "sccp.sequencing_segmenting.more",
+ FT_UINT8, BASE_HEX, VALS(sccp_segmenting_reassembling_values), SEQUENCING_SEGMENTING_MORE_MASK,
+ "", HFILL}},
+ { &hf_sccp_credit,
+ { "Credit", "sccp.credit",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_release_cause,
+ { "Release Cause", "sccp.release_cause",
+ FT_UINT8, BASE_HEX, VALS(sccp_release_cause_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_return_cause,
+ { "Return Cause", "sccp.return_cause",
+ FT_UINT8, BASE_HEX, VALS(sccp_return_cause_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_reset_cause,
+ { "Reset Cause", "sccp.reset_cause",
+ FT_UINT8, BASE_HEX, VALS(sccp_reset_cause_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_error_cause,
+ { "Error Cause", "sccp.error_cause",
+ FT_UINT8, BASE_HEX, VALS(sccp_error_cause_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_refusal_cause,
+ { "Refusal Cause", "sccp.refusal_cause",
+ FT_UINT8, BASE_HEX, VALS(sccp_refusal_cause_values), 0x0,
+ "", HFILL}},
+ { &hf_sccp_segmentation_first,
+ { "Segmentation: First", "sccp.segmentation.first",
+ FT_UINT8, BASE_HEX, VALS(sccp_segmentation_first_segment_values), SEGMENTATION_FIRST_SEGMENT_MASK,
+ "", HFILL}},
+ { &hf_sccp_segmentation_class,
+ { "Segmentation: Class", "sccp.segmentation.class",
+ FT_UINT8, BASE_HEX, VALS(sccp_segmentation_class_values), SEGMENTATION_CLASS_MASK,
+ "", HFILL}},
+ { &hf_sccp_segmentation_remaining,
+ { "Segmentation: Remaining", "sccp.segmentation.remaining",
+ FT_UINT8, BASE_HEX, NULL, SEGMENTATION_REMAINING_MASK,
+ "", HFILL}},
+ { &hf_sccp_segmentation_slr,
+ { "Segmentation: Source Local Reference", "sccp.segmentation.slr",
+ FT_UINT24, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_hop_counter,
+ { "Hop Counter", "sccp.hops",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL}},
+ { &hf_sccp_importance,
+ { "Importance", "sccp.importance",
+ FT_UINT8, BASE_HEX, NULL, IMPORTANCE_IMPORTANCE_MASK,
+ "", HFILL}},
+
+ /* ISNI is ANSI only */
+ { &hf_sccp_ansi_isni_mi,
+ { "ISNI Mark for Identification Indicator", "sccp.isni.mi",
+ FT_UINT8, BASE_HEX, VALS(sccp_isni_mark_for_id_values), ANSI_ISNI_MI_MASK,
+ "", HFILL}},
+ { &hf_sccp_ansi_isni_iri,
+ { "ISNI Routing Indicator", "sccp.isni.iri",
+ FT_UINT8, BASE_HEX, VALS(sccp_isni_iri_values), ANSI_ISNI_IRI_MASK,
+ "", HFILL}},
+ { &hf_sccp_ansi_isni_ti,
+ { "ISNI Type Indicator", "sccp.isni.ti",
+ FT_UINT8, BASE_HEX, VALS(sccp_isni_ti_values), ANSI_ISNI_TI_MASK,
+ "", HFILL}},
+ { &hf_sccp_ansi_isni_netspec,
+ { "ISNI Network Specific (Type 1)", "sccp.isni.netspec",
+ FT_UINT8, BASE_HEX, NULL, ANSI_ISNI_NETSPEC_MASK,
+ "", HFILL}},
+ { &hf_sccp_ansi_isni_counter,
+ { "ISNI Counter", "sccp.isni.counter",
+ FT_UINT8, BASE_HEX, NULL, ANSI_ISNI_COUNTER_MASK,
+ "", HFILL}},
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_sccp,
+ &ett_sccp_called,
+ &ett_sccp_called_ai,
+ &ett_sccp_called_pc,
+ &ett_sccp_called_gt,
+ &ett_sccp_calling,
+ &ett_sccp_calling_ai,
+ &ett_sccp_calling_pc,
+ &ett_sccp_calling_gt,
+ &ett_sccp_sequencing_segmenting,
+ &ett_sccp_segmentation,
+ &ett_sccp_ansi_isni_routing_control,
+ };
+
+ /* Register the protocol name and description */
+ proto_sccp = proto_register_protocol("Signalling Connection Control Part",
+ "SCCP", "sccp");
+
+ register_dissector("sccp", dissect_sccp, proto_sccp);
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_sccp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ sccp_ssn_dissector_table = register_dissector_table("sccp.ssn", "SCCP SSN", FT_UINT8, BASE_DEC);
+
+ register_heur_dissector_list("sccp", &heur_subdissector_list);
+
+ sccp_module = prefs_register_protocol(proto_sccp, NULL);
+
+ prefs_register_uint_preference(sccp_module, "source_pc",
+ "Source PC",
+ "The source point code (usually MSC) (to determine whether message is uplink or downlink)",
+ 16, &sccp_source_pc_global);
+
+ prefs_register_bool_preference(sccp_module, "show_length",
+ "Show length",
+ "Show parameter length in the protocol tree",
+ &sccp_show_length);
+}
+
+void
+proto_reg_handoff_sccp(void)
+{
+ dissector_handle_t sccp_handle;
+
+ sccp_handle = find_dissector("sccp");
+
+ dissector_add("mtp3.service_indicator", SCCP_SI, sccp_handle);
+ dissector_add("m3ua.protocol_data_si", SCCP_SI, sccp_handle);
+
+ data_handle = find_dissector("data");
+}