Move sourcelists into Makefile.common
[obnox/wireshark/wip.git] / packet-sccp.c
index 20e90400884272a276551d4f0b570811ba069012..d9c4ef5c72bb71ac6fa7c59766e15cbc790536b4 100644 (file)
@@ -8,7 +8,7 @@
  *
  * Copyright 2002, Jeff Morriss <jeff.morriss[AT]ulticom.com>
  *
- * $Id: packet-sccp.c,v 1.10 2003/04/19 20:13:22 tuexen Exp $
+ * $Id: packet-sccp.c,v 1.20 2004/01/08 20:19:03 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -47,6 +47,7 @@
 
 #include <epan/packet.h>
 #include "packet-mtp3.h"
+#include "prefs.h"
 
 #define SCCP_SI 3
 
@@ -266,6 +267,9 @@ static const value_string sccp_ssn_values[] = {
   { 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 } };
 
 
@@ -648,6 +652,15 @@ 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
@@ -672,14 +685,14 @@ dissect_sccp_unknown_message(tvbuff_t *message_tvb, proto_tree *sccp_tree)
 }
 
 static void
-dissect_sccp_unknown_param(tvbuff_t *tvb, proto_tree *tree, guint8 type, guint16 length)
+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, guint8 length)
+dissect_sccp_dlr_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint32 reference;
 
@@ -688,7 +701,7 @@ dissect_sccp_dlr_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_slr_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_slr_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint32 reference;
 
@@ -698,10 +711,10 @@ dissect_sccp_slr_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 
 static void
 dissect_sccp_gt_address_information(tvbuff_t *tvb, proto_tree *tree,
-                                   guint8 length, gboolean even_length,
+                                   guint length, gboolean even_length,
                                    gboolean called)
 {
-  guint8 offset = 0;
+  guint offset = 0;
   guint8 odd_signal, even_signal = 0x0f;
   char gt_digits[GT_MAX_SIGNALS] = { 0 };
 
@@ -734,13 +747,13 @@ dissect_sccp_gt_address_information(tvbuff_t *tvb, proto_tree *tree,
 }
 
 static void
-dissect_sccp_global_title(tvbuff_t *tvb, proto_tree *tree, guint8 length,
+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;
-  guint8 offset = 0;
+  guint offset = 0;
   guint8 odd_even, nai, tt, np, es;
   gboolean even = TRUE;
 
@@ -816,6 +829,8 @@ dissect_sccp_global_title(tvbuff_t *tvb, proto_tree *tree, guint8 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),
@@ -824,7 +839,7 @@ dissect_sccp_global_title(tvbuff_t *tvb, proto_tree *tree, guint8 length,
 }
 
 static int
-dissect_sccp_3byte_pc(tvbuff_t *tvb, proto_tree *call_tree, guint8 offset,
+dissect_sccp_3byte_pc(tvbuff_t *tvb, proto_tree *call_tree, guint offset,
                      gboolean called)
 {
   guint32 dpc;
@@ -892,11 +907,11 @@ dissect_sccp_3byte_pc(tvbuff_t *tvb, proto_tree *call_tree, guint8 offset,
  */
 static void
 dissect_sccp_called_calling_param(tvbuff_t *tvb, proto_tree *tree,
-                                 guint8 length, gboolean called)
+                                 guint length, gboolean called)
 {
   proto_item *call_item = 0, *call_ai_item = 0;
   proto_tree *call_tree = 0, *call_ai_tree = 0;
-  guint8 offset;
+  guint offset;
   guint8 national = -1, routing_ind, gti, pci, ssni, ssn;
   guint32 dpc;
   tvbuff_t *gt_tvb;
@@ -990,6 +1005,8 @@ dissect_sccp_called_calling_param(tvbuff_t *tvb, proto_tree *tree,
 
     /* 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,
@@ -1042,6 +1059,8 @@ dissect_sccp_called_calling_param(tvbuff_t *tvb, proto_tree *tree,
 
     /* 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,
@@ -1053,19 +1072,19 @@ dissect_sccp_called_calling_param(tvbuff_t *tvb, proto_tree *tree,
 }
 
 static void
-dissect_sccp_called_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+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, guint8 length)
+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, guint8 length)
+dissect_sccp_class_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 class, handling;
 
@@ -1079,7 +1098,7 @@ dissect_sccp_class_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_segmenting_reassembling_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_segmenting_reassembling_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 more;
 
@@ -1088,7 +1107,7 @@ dissect_sccp_segmenting_reassembling_param(tvbuff_t *tvb, proto_tree *tree, guin
 }
 
 static void
-dissect_sccp_receive_sequence_number_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_receive_sequence_number_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 rsn;
 
@@ -1097,7 +1116,7 @@ dissect_sccp_receive_sequence_number_param(tvbuff_t *tvb, proto_tree *tree, guin
 }
 
 static void
-dissect_sccp_sequencing_segmenting_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_sequencing_segmenting_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 rsn, ssn, more;
   proto_item *param_item;
@@ -1124,7 +1143,7 @@ dissect_sccp_sequencing_segmenting_param(tvbuff_t *tvb, proto_tree *tree, guint8
 }
 
 static void
-dissect_sccp_credit_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_credit_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 credit;
 
@@ -1133,7 +1152,7 @@ dissect_sccp_credit_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_release_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_release_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 cause;
 
@@ -1142,7 +1161,7 @@ dissect_sccp_release_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_return_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_return_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 cause;
 
@@ -1151,7 +1170,7 @@ dissect_sccp_return_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_reset_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_reset_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 cause;
 
@@ -1160,7 +1179,7 @@ dissect_sccp_reset_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_error_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_error_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 cause;
 
@@ -1169,7 +1188,7 @@ dissect_sccp_error_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_refusal_cause_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_refusal_cause_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 cause;
 
@@ -1191,12 +1210,18 @@ dissect_sccp_data_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                          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, guint8 length)
+dissect_sccp_segmentation_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 first, class, remaining;
   guint32 slr;
@@ -1225,7 +1250,7 @@ dissect_sccp_segmentation_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_hop_counter_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_hop_counter_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 hops;
 
@@ -1234,7 +1259,7 @@ dissect_sccp_hop_counter_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_importance_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_importance_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 importance;
 
@@ -1243,10 +1268,10 @@ dissect_sccp_importance_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
 }
 
 static void
-dissect_sccp_isni_param(tvbuff_t *tvb, proto_tree *tree, guint8 length)
+dissect_sccp_isni_param(tvbuff_t *tvb, proto_tree *tree, guint length)
 {
   guint8 mi, iri, ti, network, netspec;
-  guint8 offset = 0;
+  guint offset = 0;
   proto_item *param_item;
   proto_tree *param_tree;
 
@@ -1462,15 +1487,15 @@ dissect_sccp_variable_parameter(tvbuff_t *tvb, packet_info *pinfo,
     length_length = PARAMETER_LONG_DATA_LENGTH_LENGTH;
   }
 
-/*  TODO? I find this annoying, but it could possibly useful for debugging.
- *  Make it a preference?
- * if (sccp_tree)
*   proto_tree_add_text(sccp_tree, tvb, offset, length_length,
*                     "%s length: %d",
*                     val_to_str(parameter_type, sccp_parameter_values,
*                                "Unknown"),
*                     parameter_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;
 
@@ -1524,6 +1549,8 @@ dissect_sccp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *sccp_tree,
     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 */
@@ -1535,6 +1562,8 @@ dissect_sccp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *sccp_tree,
     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;
 
 
@@ -1889,10 +1918,21 @@ 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))
-    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCCP");
+    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. */
@@ -1902,6 +1942,37 @@ dissect_sccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     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);
 }
@@ -2218,15 +2289,15 @@ proto_register_sccp(void)
     /* ISNI is ANSI only */
     { &hf_sccp_ansi_isni_mi,
       { "ISNI Mark for Identification Indicator", "sccp.isni.mi",
-       FT_UINT8, BASE_HEX, NULL, ANSI_ISNI_MI_MASK,
+       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, NULL, ANSI_ISNI_IRI_MASK,
+       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, NULL, ANSI_ISNI_TI_MASK,
+       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",
@@ -2258,12 +2329,27 @@ proto_register_sccp(void)
   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
@@ -2271,7 +2357,7 @@ proto_reg_handoff_sccp(void)
 {
   dissector_handle_t sccp_handle;
 
-  sccp_handle = create_dissector_handle(dissect_sccp, proto_sccp);
+  sccp_handle = find_dissector("sccp");
 
   dissector_add("mtp3.service_indicator", SCCP_SI, sccp_handle);
   dissector_add("m3ua.protocol_data_si", SCCP_SI, sccp_handle);