As with "file_write_error_message()", so with
[obnox/wireshark/wip.git] / packet-mtp3mg.c
index a6a358aeafc02154798f0757e8686ce908bb5841..eeb8b2cfe319cd4f3d39ff3852d9d5e7b9758044 100644 (file)
@@ -1,14 +1,16 @@
 /* packet-mtp3mg.c
  * Routines for Message Transfer Part Level 3 Management and Test dissection
+ *
  * It is (hopefully) compliant to:
  *   ANSI T1.111.4-1996
  *   ITU-T Q.704 7/1996
  *   ITU-T Q.707 7/1996 and ANSI T1.111.7-1996 (for SLT message formats)
- *   and portions of ITU-T Q.2210 7/1996 (for XCO/XCA message formats)
+ *   portions of ITU-T Q.2210 7/1996 (for XCO/XCA message formats)
+ *   GF 001-9001 (Chinese ITU variant)
  *
  * Copyright 2003, Jeff Morriss <jeff.morriss[AT]ulticom.com>
  *
- * $Id: packet-mtp3mg.c,v 1.1 2003/01/02 20:44:32 guy Exp $
+ * $Id: packet-mtp3mg.c,v 1.11 2003/12/06 19:14:30 jmayer Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include "prefs.h"
 
 #include <packet-mtp3.h>
-extern Standard_Type mtp3_standard;
 
 /* MTP3 Service Indicators used by this dissector */
 #define MTP3MG_SI 0
 #define MTP3MG_ITU_TEST_SI 1
 #define MTP3MG_ANSI_TEST_SI 2
 
-/* SS7 is little-endian */
-#define BYTE_ORDER TRUE
-
 #define H0H1_LENGTH 1
 #define H0_MASK     0x0f
 #define H1_MASK     0xf0
@@ -366,16 +364,19 @@ static int hf_mtp3mg_tfc_apc_network = -1;
 static int hf_mtp3mg_tfc_ansi_status = -1;
 static int hf_mtp3mg_tfc_itu_apc = -1;
 static int hf_mtp3mg_tfc_itu_status = -1;
+static int hf_mtp3mg_tfc_chinese_apc = -1;
 static int hf_mtp3mg_tfm_ansi_apc = -1;
 static int hf_mtp3mg_tfm_apc_member = -1;
 static int hf_mtp3mg_tfm_apc_cluster = -1;
 static int hf_mtp3mg_tfm_apc_network = -1;
 static int hf_mtp3mg_tfm_itu_apc = -1;
+static int hf_mtp3mg_tfm_chinese_apc = -1;
 static int hf_mtp3mg_rsm_ansi_apc = -1;
 static int hf_mtp3mg_rsm_apc_member = -1;
 static int hf_mtp3mg_rsm_apc_cluster = -1;
 static int hf_mtp3mg_rsm_apc_network = -1;
 static int hf_mtp3mg_rsm_itu_apc = -1;
+static int hf_mtp3mg_rsm_chinese_apc = -1;
 static int hf_mtp3mg_mim_ansi_slc = -1;
 static int hf_mtp3mg_dlc_ansi_slc = -1;
 static int hf_mtp3mg_dlc_ansi_link = -1;
@@ -385,6 +386,7 @@ static int hf_mtp3mg_upu_apc_member = -1;
 static int hf_mtp3mg_upu_apc_cluster = -1;
 static int hf_mtp3mg_upu_apc_network = -1;
 static int hf_mtp3mg_upu_itu_apc = -1;
+static int hf_mtp3mg_upu_chinese_apc = -1;
 static int hf_mtp3mg_upu_user = -1;
 static int hf_mtp3mg_upu_cause = -1;
 static int hf_mtp3test_h0 = -1;
@@ -414,9 +416,9 @@ dissect_mtp3mg_chm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                   guint8 h1)
 {
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, chm_h1_message_type_acro_values, "Unknown"));
-
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, chm_h1_message_type_acro_values, "Unknown"));
+       
     switch (h1)
     {
     case CHM_H1_COO:
@@ -424,12 +426,12 @@ dissect_mtp3mg_chm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        if (mtp3_standard == ANSI_STANDARD)
        {
            proto_tree_add_item(tree, hf_mtp3mg_coo_ansi_slc, tvb, 0,
-                               COO_LENGTH, BYTE_ORDER);
+                               COO_LENGTH, TRUE);
            proto_tree_add_item(tree, hf_mtp3mg_coo_ansi_fsn, tvb, 0,
-                               COO_LENGTH, BYTE_ORDER);
-       } else {
+                               COO_LENGTH, TRUE);
+       } else /* ITU_STANDARD and CHINESE_ITU_STANDARD */ {
            proto_tree_add_item(tree, hf_mtp3mg_coo_itu_fsn, tvb, 0,
-                               COO_LENGTH, BYTE_ORDER);
+                               COO_LENGTH, TRUE);
        }
        break;
 
@@ -441,9 +443,9 @@ dissect_mtp3mg_chm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                ANSI_XCO_LENGTH, TRUE);
            proto_tree_add_item(tree, hf_mtp3mg_xco_ansi_fsn, tvb, 0,
                                ANSI_XCO_LENGTH, TRUE);
-       } else {
+       } else /* ITU_STANDARD and CHINESE_ITU_STANDARD */ {
            proto_tree_add_item(tree, hf_mtp3mg_xco_itu_fsn, tvb, 0,
-                               ITU_XCO_LENGTH, BYTE_ORDER);
+                               ITU_XCO_LENGTH, TRUE);
        }
        break;
 
@@ -455,9 +457,9 @@ dissect_mtp3mg_chm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                ANSI_CBD_LENGTH, TRUE);
            proto_tree_add_item(tree, hf_mtp3mg_cbd_ansi_cbc, tvb, 0,
                                ANSI_CBD_LENGTH, TRUE);
-       } else {
+       } else /* ITU_STANDARD and CHINESE_ITU_STANDARD */ {
            proto_tree_add_item(tree, hf_mtp3mg_cbd_itu_cbc, tvb, 0,
-                               ITU_CBD_LENGTH, BYTE_ORDER);
+                               ITU_CBD_LENGTH, TRUE);
        }
        break;
 
@@ -471,8 +473,8 @@ dissect_mtp3mg_ecm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                   guint8 h1)
 {
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, ecm_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, ecm_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
@@ -481,7 +483,7 @@ dissect_mtp3mg_ecm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        if (mtp3_standard == ANSI_STANDARD)
        {
            proto_tree_add_item(tree, hf_mtp3mg_eco_ansi_slc, tvb, 0,
-                               ANSI_ECO_LENGTH, BYTE_ORDER);
+                               ANSI_ECO_LENGTH, TRUE);
        }
        /* else: nothing to dissect */
        break;
@@ -492,17 +494,44 @@ dissect_mtp3mg_ecm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 }
 
 static void
-dissect_mtp3mg_fcm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
-                  guint8 h1)
+dissect_mtp3mg_3byte_pc(tvbuff_t *tvb, proto_tree *tree, gint *ett_pc,
+                       int *hf_pc, int *hf_pc_member, int *hf_pc_cluster,
+                       int *hf_pc_network)
 {
     guint32 apc;
     proto_item *apc_item;
     proto_tree *apc_tree;
     char pc[ANSI_PC_STRING_LENGTH];
 
+    apc = tvb_get_ntoh24(tvb, 0);
+
+    snprintf(pc, sizeof(pc), "%d-%d-%d",
+            (apc & ANSI_NETWORK_MASK),
+            ((apc & ANSI_CLUSTER_MASK) >> 8),
+            ((apc & ANSI_MEMBER_MASK) >> 16));
+
+    apc_item = proto_tree_add_string_format(tree, *hf_pc, tvb, 0,
+                                           ANSI_PC_LENGTH, pc,
+                                           "Affected PC (%s)", pc);
+
+    apc_tree = proto_item_add_subtree(apc_item, *ett_pc);
+
+    proto_tree_add_uint(apc_tree, *hf_pc_member, tvb,
+                       ANSI_MEMBER_OFFSET, ANSI_NCM_LENGTH, apc);
+    proto_tree_add_uint(apc_tree, *hf_pc_cluster, tvb,
+                       ANSI_CLUSTER_OFFSET, ANSI_NCM_LENGTH, apc);
+    proto_tree_add_uint(apc_tree, *hf_pc_network, tvb,
+                       ANSI_NETWORK_OFFSET, ANSI_NCM_LENGTH, apc);
+
+}
+
+static void
+dissect_mtp3mg_fcm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+                  guint8 h1)
+{
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, fcm_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, fcm_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
@@ -511,39 +540,40 @@ dissect_mtp3mg_fcm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        break;
 
     case FCM_H1_TFC:
-       if (mtp3_standard == ANSI_STANDARD)
-       {
-           apc = tvb_get_ntoh24(tvb, 0);
+       if (mtp3_standard == ITU_STANDARD) {
+
+           proto_tree_add_item(tree, hf_mtp3mg_tfc_itu_apc, tvb, 0,
+                               ITU_PC_LENGTH, TRUE);
+
+           /* Congestion level is a national option */
+           proto_tree_add_item(tree, hf_mtp3mg_tfc_itu_status, tvb, 0,
+                               ITU_TFC_STATUS_LENGTH, TRUE);
+
 
-           snprintf(pc, sizeof(pc), "%d-%d-%d",
-                    (apc & ANSI_NETWORK_MASK),
-                    ((apc & ANSI_CLUSTER_MASK) >> 8),
-                    ((apc & ANSI_MEMBER_MASK) >> 16));
 
-           apc_item = proto_tree_add_string_format(tree,
-                                                   hf_mtp3mg_tfc_ansi_apc,
-                                                   tvb, 0, ANSI_PC_LENGTH, pc,
-                                                   "Affected PC (%s)", pc);
+       } else /* ANSI_STANDARD and CHINESE_ITU_STANDARD */ {
 
-           apc_tree = proto_item_add_subtree(apc_item, ett_mtp3mg_fcm_apc);
+           int *hf_apc_string;
 
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_tfc_apc_member, tvb,
-                               ANSI_MEMBER_OFFSET, ANSI_NCM_LENGTH, apc);
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_tfc_apc_cluster, tvb,
-                               ANSI_CLUSTER_OFFSET, ANSI_NCM_LENGTH, apc);
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_tfc_apc_network, tvb,
-                               ANSI_NETWORK_OFFSET, ANSI_NCM_LENGTH, apc);
+           if (mtp3_standard == ANSI_STANDARD) {
+
+               hf_apc_string = &hf_mtp3mg_tfc_ansi_apc;
+
+           } else /* CHINESE_ITU_STANDARD */ {
+
+               hf_apc_string = &hf_mtp3mg_tfc_chinese_apc;
+           }
+
+           dissect_mtp3mg_3byte_pc(tvb, tree, &ett_mtp3mg_fcm_apc,
+                                   hf_apc_string,
+                                   &hf_mtp3mg_tfc_apc_member,
+                                   &hf_mtp3mg_tfc_apc_cluster,
+                                   &hf_mtp3mg_tfc_apc_network);
 
            proto_tree_add_item(tree, hf_mtp3mg_tfc_ansi_status, tvb,
                                ANSI_TFC_STATUS_OFFSET, ANSI_TFC_STATUS_LENGTH,
-                               BYTE_ORDER);
-       } else {
-           proto_tree_add_item(tree, hf_mtp3mg_tfc_itu_apc, tvb, 0,
-                               ITU_PC_LENGTH, BYTE_ORDER);
+                               TRUE);
 
-           /* Congestion level is a national option */
-           proto_tree_add_item(tree, hf_mtp3mg_tfc_itu_status, tvb, 0,
-                               ITU_TFC_STATUS_LENGTH, BYTE_ORDER);
        }
        break;
 
@@ -556,14 +586,9 @@ static void
 dissect_mtp3mg_tfm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                   guint8 h1)
 {
-    guint32 apc;
-    proto_item *apc_item;
-    proto_tree *apc_tree;
-    char pc[ANSI_PC_STRING_LENGTH];
-
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, tfm_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, tfm_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
@@ -575,32 +600,25 @@ dissect_mtp3mg_tfm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     case TFM_H1_TCA:
        if (mtp3_standard == ANSI_STANDARD)
        {
-           apc = tvb_get_ntoh24(tvb, 0);
-
-           snprintf(pc, sizeof(pc), "%d-%d-%d",
-                    (apc & ANSI_NETWORK_MASK),
-                    ((apc & ANSI_CLUSTER_MASK) >> 8),
-                    ((apc & ANSI_MEMBER_MASK) >> 16));
-
-           apc_item = proto_tree_add_string_format(tree,
-                                                   hf_mtp3mg_tfm_ansi_apc,
-                                                   tvb, 0, ANSI_PC_LENGTH, pc,
-                                                   "Affected PC (%s)", pc);
-
-           apc_tree = proto_item_add_subtree(apc_item, ett_mtp3mg_tfm_apc);
-
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_tfm_apc_member, tvb,
-                               ANSI_MEMBER_OFFSET, ANSI_NCM_LENGTH, apc);
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_tfm_apc_cluster, tvb,
-                               ANSI_CLUSTER_OFFSET, ANSI_NCM_LENGTH, apc);
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_tfm_apc_network, tvb,
-                               ANSI_NETWORK_OFFSET, ANSI_NCM_LENGTH, apc);
-       } else {
+           dissect_mtp3mg_3byte_pc(tvb, tree, &ett_mtp3mg_tfm_apc,
+                                   &hf_mtp3mg_tfm_ansi_apc,
+                                   &hf_mtp3mg_tfm_apc_member,
+                                   &hf_mtp3mg_tfm_apc_cluster,
+                                   &hf_mtp3mg_tfm_apc_network);
+
+       } else /* ITU_STANDARD and CHINESE_ITU_STANDARD */ {
+
            if (h1 == TFM_H1_TCP || h1 == TFM_H1_TCR || h1 == TFM_H1_TCA)
                dissect_mtp3mg_unknown_message(tvb, tree);
-           else
+           else if (mtp3_standard == ITU_STANDARD)
                proto_tree_add_item(tree, hf_mtp3mg_tfm_itu_apc, tvb, 0,
-                                   ITU_PC_LENGTH, BYTE_ORDER);
+                                   ITU_PC_LENGTH, TRUE);
+           else /* CHINESE_ITU_STANDARD */
+               dissect_mtp3mg_3byte_pc(tvb, tree, &ett_mtp3mg_tfm_apc,
+                                       &hf_mtp3mg_tfm_chinese_apc,
+                                       &hf_mtp3mg_tfm_apc_member,
+                                       &hf_mtp3mg_tfm_apc_cluster,
+                                       &hf_mtp3mg_tfm_apc_network);
        }
        break;
 
@@ -613,14 +631,9 @@ static void
 dissect_mtp3mg_rsm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                   guint8 h1)
 {
-    guint32 apc;
-    proto_item *apc_item;
-    proto_tree *apc_tree;
-    char pc[ANSI_PC_STRING_LENGTH];
-
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, rsm_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, rsm_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
@@ -630,31 +643,27 @@ dissect_mtp3mg_rsm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     case RSM_H1_RCR:
        if (mtp3_standard == ANSI_STANDARD)
        {
-           apc = tvb_get_ntoh24(tvb, 0);
-
-           snprintf(pc, sizeof(pc), "%d-%d-%d",
-                    (apc & ANSI_NETWORK_MASK),
-                    ((apc & ANSI_CLUSTER_MASK) >> 8),
-                    ((apc & ANSI_MEMBER_MASK) >> 16));
-
-           apc_item = proto_tree_add_string_format(tree,
-                                                   hf_mtp3mg_rsm_ansi_apc,
-                                                   tvb, 0, ANSI_PC_LENGTH, pc,
-                                                   "Affected PC (%s)", pc);
-
-           apc_tree = proto_item_add_subtree(apc_item, ett_mtp3mg_rsm_apc);
-
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_rsm_apc_member, tvb,
-                               ANSI_MEMBER_OFFSET, ANSI_NCM_LENGTH, apc);
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_rsm_apc_cluster, tvb,
-                               ANSI_CLUSTER_OFFSET, ANSI_NCM_LENGTH, apc);
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_rsm_apc_network, tvb,
-                               ANSI_NETWORK_OFFSET, ANSI_NCM_LENGTH, apc);
-       } else {
+           dissect_mtp3mg_3byte_pc(tvb, tree, &ett_mtp3mg_rsm_apc,
+                                   &hf_mtp3mg_rsm_ansi_apc,
+                                   &hf_mtp3mg_rsm_apc_member,
+                                   &hf_mtp3mg_rsm_apc_cluster,
+                                   &hf_mtp3mg_rsm_apc_network);
+
+       } else /* ITU_STANDARD and CHINESE_ITU_STANDARD */ {
+
            if (h1 == RSM_H1_RST || h1 == RSM_H1_RSR)
-               proto_tree_add_item(tree, hf_mtp3mg_rsm_itu_apc, tvb, 0,
-                                   ITU_PC_LENGTH, BYTE_ORDER);
-           else
+           {
+               if (mtp3_standard == ITU_STANDARD)
+                   proto_tree_add_item(tree, hf_mtp3mg_rsm_itu_apc, tvb, 0,
+                                       ITU_PC_LENGTH, TRUE);
+
+               else /* CHINESE_ITU_STANDARD */
+                   dissect_mtp3mg_3byte_pc(tvb, tree, &ett_mtp3mg_rsm_apc,
+                                           &hf_mtp3mg_rsm_chinese_apc,
+                                           &hf_mtp3mg_rsm_apc_member,
+                                           &hf_mtp3mg_rsm_apc_cluster,
+                                           &hf_mtp3mg_rsm_apc_network);
+           } else
                dissect_mtp3mg_unknown_message(tvb, tree);
        }
        break;
@@ -669,8 +678,8 @@ dissect_mtp3mg_mim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                   guint8 h1)
 {
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, mim_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, mim_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
@@ -685,7 +694,7 @@ dissect_mtp3mg_mim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        if (mtp3_standard == ANSI_STANDARD)
        {
            proto_tree_add_item(tree, hf_mtp3mg_mim_ansi_slc, tvb, 0,
-                               ANSI_MIM_LENGTH, BYTE_ORDER);
+                               ANSI_MIM_LENGTH, TRUE);
        }
        /* else: nothing to dissect */
        break;
@@ -700,8 +709,8 @@ dissect_mtp3mg_trm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                   guint8 h1)
 {
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, trm_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, trm_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
@@ -724,8 +733,8 @@ dissect_mtp3mg_dlm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                   guint8 h1)
 {
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, dlm_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, dlm_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
@@ -733,12 +742,12 @@ dissect_mtp3mg_dlm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        if (mtp3_standard == ANSI_STANDARD)
        {
            proto_tree_add_item(tree, hf_mtp3mg_dlc_ansi_slc, tvb, 0,
-                               ANSI_DLC_LENGTH, BYTE_ORDER);
+                               ANSI_DLC_LENGTH, TRUE);
            proto_tree_add_item(tree, hf_mtp3mg_dlc_ansi_link, tvb, 0,
-                               ANSI_DLC_LENGTH, BYTE_ORDER);
-       } else {
+                               ANSI_DLC_LENGTH, TRUE);
+       } else /* ITU_STANDARD and CHINESE_ITU_STANDARD */ {
            proto_tree_add_item(tree, hf_mtp3mg_dlc_itu_link, tvb, 0,
-                               ITU_DLC_LENGTH, BYTE_ORDER);
+                               ITU_DLC_LENGTH, TRUE);
        }
        break;
     case DLM_H1_CSS:
@@ -756,52 +765,40 @@ static void
 dissect_mtp3mg_ufc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                   guint8 h1)
 {
-    guint32 apc;
-    proto_item *apc_item;
-    proto_tree *apc_tree;
-    char pc[ANSI_PC_STRING_LENGTH];
-
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, ufc_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, ufc_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
     case UFC_H1_UPU:
-       if (mtp3_standard == ANSI_STANDARD)
+       if (mtp3_standard == ANSI_STANDARD
+           || mtp3_standard == CHINESE_ITU_STANDARD)
        {
-           apc = tvb_get_ntoh24(tvb, 0);
-
-           snprintf(pc, sizeof(pc), "%d-%d-%d",
-                    (apc & ANSI_NETWORK_MASK),
-                    ((apc & ANSI_CLUSTER_MASK) >> 8),
-                    ((apc & ANSI_MEMBER_MASK) >> 16));
+           int *hf_apc;
 
-           apc_item = proto_tree_add_string_format(tree,
-                                                   hf_mtp3mg_upu_ansi_apc,
-                                                   tvb, 0, ANSI_PC_LENGTH, pc,
-                                                   "Affected PC (%s)", pc);
+           if (mtp3_standard == ANSI_STANDARD)
+               hf_apc = &hf_mtp3mg_upu_ansi_apc;
+           else /* CHINESE_ITU_STANDARD */
+               hf_apc = &hf_mtp3mg_upu_chinese_apc;
 
-           apc_tree = proto_item_add_subtree(apc_item, ett_mtp3mg_upu_apc);
-
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_upu_apc_member, tvb,
-                               ANSI_MEMBER_OFFSET, ANSI_NCM_LENGTH, apc);
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_upu_apc_cluster, tvb,
-                               ANSI_CLUSTER_OFFSET, ANSI_NCM_LENGTH, apc);
-           proto_tree_add_uint(apc_tree, hf_mtp3mg_upu_apc_network, tvb,
-                               ANSI_NETWORK_OFFSET, ANSI_NCM_LENGTH, apc);
+           dissect_mtp3mg_3byte_pc(tvb, tree, &ett_mtp3mg_upu_apc,
+                                   hf_apc,
+                                   &hf_mtp3mg_rsm_apc_member,
+                                   &hf_mtp3mg_rsm_apc_cluster,
+                                   &hf_mtp3mg_rsm_apc_network);
 
            proto_tree_add_item(tree, hf_mtp3mg_upu_user, tvb,
-                               ANSI_UPU_USER_OFFSET, UPU_USER_LENGTH, BYTE_ORDER);
+                               ANSI_UPU_USER_OFFSET, UPU_USER_LENGTH, TRUE);
            proto_tree_add_item(tree, hf_mtp3mg_upu_cause, tvb,
-                               ANSI_UPU_USER_OFFSET, UPU_USER_LENGTH, BYTE_ORDER);
-       } else {
+                               ANSI_UPU_USER_OFFSET, UPU_USER_LENGTH, TRUE);
+       } else /* ITU_STANDARD */ {
            proto_tree_add_item(tree, hf_mtp3mg_upu_itu_apc, tvb, 0,
-                               ITU_PC_LENGTH, BYTE_ORDER);
+                               ITU_PC_LENGTH, TRUE);
            proto_tree_add_item(tree, hf_mtp3mg_upu_user, tvb,
-                               ITU_UPU_USER_OFFSET, UPU_USER_LENGTH, BYTE_ORDER);
+                               ITU_UPU_USER_OFFSET, UPU_USER_LENGTH, TRUE);
            proto_tree_add_item(tree, hf_mtp3mg_upu_cause, tvb,
-                               ITU_UPU_USER_OFFSET, UPU_USER_LENGTH, BYTE_ORDER);
+                               ITU_UPU_USER_OFFSET, UPU_USER_LENGTH, TRUE);
        }
        break;
 
@@ -817,15 +814,15 @@ dissect_mtp3mg_test(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     guint8 length;
 
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-                       val_to_str(h1, test_h1_message_type_acro_values, "Unknown"));
+       col_add_fstr(pinfo->cinfo, COL_INFO, "%s ",
+                    val_to_str(h1, test_h1_message_type_acro_values, "Unknown"));
 
     switch (h1)
     {
     case TEST_H1_SLTM:
     case TEST_H1_SLTA:
        proto_tree_add_item(tree, hf_mtp3mg_test_length, tvb, 0, TEST_LENGTH,
-                           BYTE_ORDER);
+                           TRUE);
 
        length = tvb_get_guint8(tvb, 0) >> TEST_LENGTH_SHIFT;
        proto_tree_add_text(tree, tvb, TEST_PATTERN_OFFSET, length,
@@ -849,14 +846,24 @@ dissect_mtp3mg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     proto_item *mtp3mg_item = NULL;
     proto_tree *mtp3mg_tree = NULL;
 
-    /* Make entries in Protocol column and Info column on summary display */
+    /* Make entries in Protocol column on summary display */
     if (check_col(pinfo->cinfo, COL_PROTOCOL))
-       col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3MG");
+      switch(mtp3_standard) {
+        case ITU_STANDARD:
+          col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3MG (Int. ITU)");
+          break;
+        case ANSI_STANDARD:
+          col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3MG (ANSI)");
+          break;
+        case CHINESE_ITU_STANDARD:
+          col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3MG (Chin. ITU)");
+          break;
+      };      
 
     if (tree) {
        /* create display subtree for the protocol */
        mtp3mg_item = proto_tree_add_item(tree, proto_mtp3mg, tvb, 0, -1,
-                                         BYTE_ORDER);
+                                         TRUE);
        mtp3mg_tree = proto_item_add_subtree(mtp3mg_item, ett_mtp3mg);
     }
 
@@ -868,7 +875,7 @@ dissect_mtp3mg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     {  /* Test messages */
 
        proto_tree_add_item(mtp3mg_tree, hf_mtp3test_h0, tvb, 0, H0H1_LENGTH,
-                           BYTE_ORDER);
+                           TRUE);
        /* H1 is added below */
 
        h0 = tvb_get_guint8(tvb, 0) & H0_MASK;
@@ -880,13 +887,13 @@ dissect_mtp3mg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        {
        case TEST_H0_SLT:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_test_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_test(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
 
        default:
            if (check_col(pinfo->cinfo, COL_INFO))
-               col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown ");
+               col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ");
 
            dissect_mtp3mg_unknown_message(tvb, mtp3mg_tree);
        } /* switch */
@@ -894,7 +901,7 @@ dissect_mtp3mg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     } else {   /* Real management messages */
 
        proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_h0, tvb, 0, H0H1_LENGTH,
-                           BYTE_ORDER);
+                           TRUE);
        /* H1 is added below */
 
        h0 = tvb_get_guint8(tvb, 0) & H0_MASK;
@@ -906,53 +913,53 @@ dissect_mtp3mg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        {
        case H0_CHM:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_chm_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_chm(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
        case H0_ECM:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_ecm_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_ecm(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
        case H0_FCM:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_fcm_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_fcm(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
        case H0_TFM:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_tfm_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_tfm(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
        case H0_RSM:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_rsm_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_rsm(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
        case H0_MIM:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_mim_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_mim(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
        case H0_TRM:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_trm_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_trm(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
        case H0_DLM:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_dlm_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_dlm(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
        case H0_UFC:
            proto_tree_add_item(mtp3mg_tree, hf_mtp3mg_ufc_h1, tvb, 0,
-                               H0H1_LENGTH, BYTE_ORDER);
+                               H0H1_LENGTH, TRUE);
            dissect_mtp3mg_ufc(payload_tvb, pinfo, mtp3mg_tree, h1);
            break;
 
        default:
            if (check_col(pinfo->cinfo, COL_INFO))
-               col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown ");
+               col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ");
 
            dissect_mtp3mg_unknown_message(tvb, mtp3mg_tree);
        } /* switch */
@@ -968,43 +975,43 @@ proto_register_mtp3mg(void)
     static hf_register_info hf[] = {
        { &hf_mtp3mg_h0,
            { "H0 (Message Group)", "mtp3mg.h0",
-             FT_UINT8, BASE_BIN, VALS(h0_message_type_values), H0_MASK,
+             FT_UINT8, BASE_HEX, VALS(h0_message_type_values), H0_MASK,
              "Message group identifier", HFILL }},
        { &hf_mtp3mg_chm_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(chm_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(chm_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_ecm_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(ecm_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(ecm_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_fcm_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(fcm_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(fcm_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_tfm_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(tfm_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(tfm_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_rsm_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(rsm_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(rsm_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_mim_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(mim_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(mim_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_trm_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(trm_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(trm_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_dlm_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(dlm_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(dlm_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_ufc_h1,
            { "H1 (Message)", "mtp3mg.h1",
-             FT_UINT8, BASE_BIN, VALS(ufc_h1_message_type_values), H1_MASK,
+             FT_UINT8, BASE_HEX, VALS(ufc_h1_message_type_values), H1_MASK,
              "Message type", HFILL }},
        { &hf_mtp3mg_coo_ansi_slc,
            { "Signalling Link Code", "mtp3mg.slc",
@@ -1074,6 +1081,10 @@ proto_register_mtp3mg(void)
            { "Status", "mtp3mg.status",
              FT_UINT8, BASE_DEC, NULL, ITU_TFC_STATUS_MASK,
              "Congestion status", HFILL }},
+       { &hf_mtp3mg_tfc_chinese_apc,
+           { "Affected Point Code", "mtp3mg.chinese_apc",
+             FT_STRING, BASE_NONE, NULL, 0x0,
+             "", HFILL }},
        { &hf_mtp3mg_tfm_ansi_apc,
            { "Affected Point Code", "mtp3mg.ansi_apc",
              FT_STRING, BASE_NONE, NULL, 0x0,
@@ -1094,6 +1105,10 @@ proto_register_mtp3mg(void)
            { "Affected Point Code (ITU)", "mtp3mg.apc",
              FT_UINT8, BASE_DEC, NULL, ITU_PC_MASK,
              "", HFILL }},
+       { &hf_mtp3mg_tfm_chinese_apc,
+           { "Affected Point Code", "mtp3mg.chinese_apc",
+             FT_STRING, BASE_NONE, NULL, 0x0,
+             "", HFILL }},
        { &hf_mtp3mg_rsm_ansi_apc,
            { "Affected Point Code", "mtp3mg.ansi_apc",
              FT_STRING, BASE_NONE, NULL, 0x0,
@@ -1114,6 +1129,10 @@ proto_register_mtp3mg(void)
            { "Affected Point Code (ITU)", "mtp3mg.apc",
              FT_UINT8, BASE_DEC, NULL, ITU_PC_MASK,
              "", HFILL }},
+       { &hf_mtp3mg_rsm_chinese_apc,
+           { "Affected Point Code", "mtp3mg.chinese_apc",
+             FT_STRING, BASE_NONE, NULL, 0x0,
+             "", HFILL }},
        { &hf_mtp3mg_mim_ansi_slc,
            { "Signalling Link Code", "mtp3mg.slc",
              FT_UINT8, BASE_DEC, NULL, ANSI_MIM_SLC_MASK,
@@ -1150,6 +1169,10 @@ proto_register_mtp3mg(void)
            { "Affected Point Code", "mtp3mg.apc",
              FT_UINT8, BASE_DEC, NULL, ITU_PC_MASK,
              "", HFILL }},
+       { &hf_mtp3mg_upu_chinese_apc,
+           { "Affected Point Code", "mtp3mg.chinese_apc",
+             FT_STRING, BASE_NONE, NULL, 0x0,
+             "", HFILL }},
        { &hf_mtp3mg_upu_user,
            { "User", "mtp3mg.user",
              FT_UINT8, BASE_HEX, VALS(service_indicator_code_vals), UPU_USER_MASK,