bugfix to a bug reported by Ian Schorr:
[obnox/wireshark/wip.git] / packet-q931.c
index f50a0c63d7ceb6c825b6e84a2c65870c7645debd..3e09da7165ff0069ef76fc4c2ff5f935d5428ee2 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for Q.931 frame disassembly
  * Guy Harris <guy@alum.mit.edu>
  *
- * $Id: packet-q931.c,v 1.72 2004/02/21 04:19:12 guy Exp $
+ * $Id: packet-q931.c,v 1.76 2004/04/17 04:43:58 guy Exp $
  *
  * Modified by Andreas Sikkema for possible use with H.323
  *
@@ -36,6 +36,7 @@
 #include <epan/strutil.h>
 #include "nlpid.h"
 #include "packet-q931.h"
+#include "packet-e164.h"
 #include "prefs.h"
 #include "reassemble.h"
 
@@ -66,6 +67,7 @@ static int hf_q931_call_ref_flag                      = -1;
 static int hf_q931_call_ref                            = -1;
 static int hf_q931_message_type                        = -1;
 static int hf_q931_segment_type                        = -1;
+static int hf_q931_cause_location                      = -1;
 static int hf_q931_cause_value                                 = -1;
 static int hf_q931_number_type                         = -1;
 static int hf_q931_numbering_plan                      = -1;
@@ -74,6 +76,8 @@ static int hf_q931_calling_party_number               = -1;
 static int hf_q931_called_party_number                         = -1;
 static int hf_q931_connected_number                    = -1;
 static int hf_q931_redirecting_number                  = -1;
+static int hf_q931_screening_ind                               = -1;
+static int hf_q931_presentation_ind                            = -1;
 
 static int hf_q931_segments = -1;
 static int hf_q931_segment = -1;
@@ -101,7 +105,7 @@ static const fragment_items q931_frag_items = {
        &hf_q931_segment_multiple_tails,
        &hf_q931_segment_too_long_segment,
        &hf_q931_segment_error,
-    &hf_q931_reassembled_in,
+       &hf_q931_reassembled_in,
        "segments"
 };
 
@@ -121,6 +125,10 @@ static gboolean q931_desegment = TRUE;
 static dissector_handle_t h225_handle;
 static dissector_handle_t q931_tpkt_pdu_handle;
 
+static void
+dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *root_tree,
+    proto_tree *q931_tree, gboolean is_tpkt, int offset, int initial_codeset);
+
 /*
  * Q.931 message types.
  */
@@ -1169,21 +1177,19 @@ dissect_q931_cause_ie(tvbuff_t *tvb, int offset, int len,
                return;
        octet = tvb_get_guint8(tvb, offset);
        coding_standard = octet & 0x60;
-       proto_tree_add_uint(tree, hf_q931_coding_standard, tvb, offset, 1, octet);
        if (coding_standard != Q931_ITU_STANDARDIZED_CODING) {
                /*
                 * We don't know how the cause is encoded,
                 * so just dump it as data and be done with it.
                 */
+               proto_tree_add_uint(tree, hf_q931_coding_standard, tvb, offset, 1, octet);
                proto_tree_add_text(tree, tvb, offset,
                    len, "Data: %s",
                    tvb_bytes_to_str(tvb, offset, len));
                return;
        }
-       proto_tree_add_text(tree, tvb, offset, 1,
-           "Location: %s",
-           val_to_str(octet & 0x0F, q931_cause_location_vals,
-             "Unknown (0x%X)"));
+       proto_tree_add_uint(tree, hf_q931_cause_location, tvb, offset, 1, octet);
+       proto_tree_add_uint(tree, hf_q931_coding_standard, tvb, offset, 1, octet);
        proto_tree_add_boolean(tree, hf_q931_extension_ind, tvb, offset, 1, octet);
        offset += 1;
        len -= 1;
@@ -1196,6 +1202,7 @@ dissect_q931_cause_ie(tvbuff_t *tvb, int offset, int len,
                    "Recommendation: %s",
                    val_to_str(octet & 0x7F, q931_cause_recommendation_vals,
                      "Unknown (0x%02X)"));
+               proto_tree_add_boolean(tree, hf_q931_extension_ind, tvb, offset, 1, octet);
                offset += 1;
                len -= 1;
        }
@@ -1205,6 +1212,7 @@ dissect_q931_cause_ie(tvbuff_t *tvb, int offset, int len,
        octet = tvb_get_guint8(tvb, offset);
        cause_value = octet & 0x7F;
        proto_tree_add_uint(tree, hf_cause_value, tvb, offset, 1, cause_value);
+       proto_tree_add_boolean(tree, hf_q931_extension_ind, tvb, offset, 1, octet);
        offset += 1;
        len -= 1;
 
@@ -2020,8 +2028,8 @@ static const value_string q931_numbering_plan_vals[] = {
 
 static const value_string q931_presentation_indicator_vals[] = {
        { 0x00, "Presentation allowed" },
-       { 0x20, "Presentation restricted" },
-       { 0x40, "Number not available due to interworking" },
+       { 0x01, "Presentation restricted" },
+       { 0x02, "Number not available due to interworking" },
        { 0,    NULL }
 };
 
@@ -2046,13 +2054,16 @@ static const value_string q931_redirection_reason_vals[] = {
 
 static void
 dissect_q931_number_ie(tvbuff_t *tvb, int offset, int len,
-    proto_tree *tree, int hfindex)
+    proto_tree *tree, int hfindex, e164_info_t e164_info)
 {
        guint8 octet;
+       gint number_plan;
 
        if (len == 0)
                return;
        octet = tvb_get_guint8(tvb, offset);
+       number_plan = octet & 0x0f;
+       e164_info.nature_of_address = ( octet & 0x70 ) >> 4;
        proto_tree_add_uint(tree, hf_q931_numbering_plan, tvb, offset, 1, octet);
        proto_tree_add_uint(tree, hf_q931_number_type, tvb, offset, 1, octet);
        proto_tree_add_boolean(tree, hf_q931_extension_ind, tvb, offset, 1, octet);
@@ -2064,14 +2075,9 @@ dissect_q931_number_ie(tvbuff_t *tvb, int offset, int len,
                if (len == 0)
                        return;
                octet = tvb_get_guint8(tvb, offset);
-               proto_tree_add_text(tree, tvb, offset, 1,
-                   "Presentation indicator: %s",
-                   val_to_str(octet & 0x60, q931_presentation_indicator_vals,
-                     "Unknown (0x%X)"));
-               proto_tree_add_text(tree, tvb, offset, 1,
-                   "Screening indicator: %s",
-                   val_to_str(octet & 0x03, q931_screening_indicator_vals,
-                     "Unknown (0x%X)"));
+               proto_tree_add_uint(tree, hf_q931_screening_ind, tvb, offset, 1, octet);
+               proto_tree_add_uint(tree, hf_q931_presentation_ind, tvb, offset, 1, octet);
+               proto_tree_add_boolean(tree, hf_q931_extension_ind, tvb, offset, 1, octet);
                offset += 1;
                len -= 1;
        }
@@ -2094,6 +2100,17 @@ dissect_q931_number_ie(tvbuff_t *tvb, int offset, int len,
        if (len == 0)
                return;
        proto_tree_add_item(tree, hfindex, tvb, offset, len, FALSE);
+       proto_item_append_text(proto_tree_get_parent(tree), ": '%s'", tvb_format_text(tvb, offset, len));
+
+       if ( number_plan == 1 ) {
+               if ( e164_info.e164_number_type != NONE ){
+
+                       e164_info.E164_number_str = tvb_get_string(tvb, offset, len);
+                       e164_info.E164_number_length = len;
+                       dissect_e164_number(tvb, tree, offset, len, e164_info);
+               }
+       }
+
 }
 
 /*
@@ -2311,6 +2328,7 @@ dissect_q931_ia5_ie(tvbuff_t *tvb, int offset, int len, proto_tree *tree,
        if (len != 0) {
                proto_tree_add_text(tree, tvb, offset, len, "%s: %s", label,
                    tvb_format_text(tvb, offset, len));
+               proto_item_append_text(proto_tree_get_parent(tree), "  '%s'", tvb_format_text(tvb, offset, len));
        }
 }
 
@@ -2381,13 +2399,13 @@ dissect_q931_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
         */
        if ((message_type != Q931_SEGMENT) || !q931_reassembly || 
                        (tvb_reported_length_remaining(tvb, offset) <= 4)) {
-               dissect_q931_IEs(tvb, pinfo, tree, q931_tree, is_tpkt, offset);
+               dissect_q931_IEs(tvb, pinfo, tree, q931_tree, is_tpkt, offset, 0);
                return;
        }
        info_element = tvb_get_guint8(tvb, offset);
        info_element_len = tvb_get_guint8(tvb, offset + 1);
        if ((info_element != Q931_IE_SEGMENTED_MESSAGE) || (info_element_len < 2)) {
-               dissect_q931_IEs(tvb, pinfo, tree, q931_tree, is_tpkt, offset);
+               dissect_q931_IEs(tvb, pinfo, tree, q931_tree, is_tpkt, offset, 0);
                return;
        }
        /* Segmented message IE */
@@ -2398,8 +2416,12 @@ dissect_q931_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                    val_to_str(info_element, q931_info_element_vals[0], "Unknown (0x%02X)"));
        proto_tree_add_text(ie_tree, tvb, offset + 1, 1, "Length: %u", info_element_len);
        dissect_q931_segmented_message_ie(tvb, offset + 2, info_element_len, ie_tree);
-    more_frags = (tvb_get_guint8(tvb, offset + 2) & 0x7F) != 0;
+       more_frags = (tvb_get_guint8(tvb, offset + 2) & 0x7F) != 0;
        segmented_message_type = tvb_get_guint8(tvb, offset + 3);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, " of %s",
+                   val_to_str(segmented_message_type, q931_message_type_vals, "Unknown message type (0x%02X)"));
+       }
        offset += 1 + 1 + info_element_len;
        /* Reassembly */
        frag_len = tvb_length_remaining(tvb, offset);
@@ -2424,13 +2446,9 @@ dissect_q931_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                } else {
                        if (tree) proto_tree_add_uint(q931_tree, hf_q931_reassembled_in, tvb, offset, frag_len, fd_head->reassembled_in);
                }
-       } else {
-               if (check_col(pinfo->cinfo, COL_INFO)) {
-                       col_append_str(pinfo->cinfo, COL_INFO, " [segment]");
-               }
        }
-    if (next_tvb)
-               dissect_q931_IEs(next_tvb, pinfo, tree, q931_tree, is_tpkt, 0);
+       if (next_tvb)
+               dissect_q931_IEs(next_tvb, pinfo, tree, q931_tree, is_tpkt, 0, 0);
 }
 
 static const value_string q931_codeset_vals[] = {
@@ -2442,9 +2460,9 @@ static const value_string q931_codeset_vals[] = {
        { 0x00, NULL },
 };
 
-void
-dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
-    proto_tree *q931_tree, gboolean is_tpkt, int offset)
+static void
+dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *root_tree,
+    proto_tree *q931_tree, gboolean is_tpkt, int offset, int initial_codeset)
 {
        proto_item      *ti;
        proto_tree      *ie_tree = NULL;
@@ -2453,8 +2471,10 @@ dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        int             codeset, locked_codeset;
        gboolean        non_locking_shift, first_segment;
        tvbuff_t        *h225_tvb, *next_tvb;
+       e164_info_t e164_info;
+       e164_info.e164_number_type = NONE;
 
-       codeset = locked_codeset = 0;   /* start out in codeset 0 */
+       codeset = locked_codeset = initial_codeset;
        non_locking_shift = TRUE;
        first_segment = FALSE;
        while (tvb_reported_length_remaining(tvb, offset) > 0) {
@@ -2611,7 +2631,7 @@ dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                            offset + 4, info_element_len - 1,
                                            info_element_len - 1);
                                        call_dissector(h225_handle, h225_tvb,
-                                           pinfo, tree);
+                                           pinfo, root_tree);
                                } else {
                                        /*
                                         * No - just show it as "User
@@ -2789,31 +2809,33 @@ dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                        break;
 
                                case CS0 | Q931_IE_CALLING_PARTY_NUMBER:
+                                       e164_info.e164_number_type = CALLING_PARTY_NUMBER;
                                        dissect_q931_number_ie(tvb,
                                            offset + 2, info_element_len,
                                            ie_tree,
-                                           hf_q931_calling_party_number);
+                                           hf_q931_calling_party_number, e164_info);
                                        break;
 
                                case CS0 | Q931_IE_CONNECTED_NUMBER_DEFAULT:
                                        dissect_q931_number_ie(tvb,
                                            offset + 2, info_element_len,
                                            ie_tree,
-                                           hf_q931_connected_number);
+                                           hf_q931_connected_number, e164_info);
                                        break;
 
                                case CS0 | Q931_IE_CALLED_PARTY_NUMBER:
+                                       e164_info.e164_number_type = CALLED_PARTY_NUMBER;
                                        dissect_q931_number_ie(tvb,
                                            offset + 2, info_element_len,
                                            ie_tree,
-                                           hf_q931_called_party_number);
+                                           hf_q931_called_party_number, e164_info);
                                        break;
 
                                case CS0 | Q931_IE_REDIRECTING_NUMBER:
                                        dissect_q931_number_ie(tvb,
                                            offset + 2, info_element_len,
                                            ie_tree,
-                                           hf_q931_redirecting_number);
+                                           hf_q931_redirecting_number, e164_info);
                                        break;
 
                                case CS0 | Q931_IE_CALLING_PARTY_SUBADDR:
@@ -2943,6 +2965,18 @@ dissect_q931(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        dissect_q931_pdu(tvb, pinfo, tree, FALSE);
 }
 
+static void
+dissect_q931_ie_cs0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_q931_IEs(tvb, pinfo, NULL, tree, FALSE, 0, 0);
+}
+
+static void
+dissect_q931_ie_cs7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_q931_IEs(tvb, pinfo, NULL, tree, FALSE, 0, 7);
+}
+
 static void 
 q931_init(void) {
        /* Initialize the fragment and reassembly tables */
@@ -2998,8 +3032,12 @@ proto_register_q931(void)
                  { "User information layer 1 protocol", "q931.uil1", FT_UINT8, BASE_HEX,
                         VALS(q931_uil1_vals), 0x1f,"", HFILL }},
 
+               { &hf_q931_cause_location,
+                 { "Cause location", "q931.cause_location", FT_UINT8, BASE_DEC, VALS(q931_cause_location_vals), 0x0f,
+                       "", HFILL }},
+
                { &hf_q931_cause_value,
-                 { "Cause value", "q931.cause_value", FT_UINT8, BASE_DEC, VALS(q931_cause_code_vals), 0x0,
+                 { "Cause value", "q931.cause_value", FT_UINT8, BASE_DEC, VALS(q931_cause_code_vals), 0x7f,
                        "", HFILL }},
 
                { &hf_q931_number_type,
@@ -3010,6 +3048,14 @@ proto_register_q931(void)
                  { "Numbering plan", "q931.numbering_plan", FT_UINT8, BASE_HEX, VALS(q931_numbering_plan_vals), 0x0f,
                        "", HFILL }},
 
+               { &hf_q931_screening_ind,
+                 { "Screening indicator", "q931.screening_ind", FT_UINT8, BASE_HEX, VALS(q931_screening_indicator_vals), 0x03,
+                       "", HFILL }},
+
+               { &hf_q931_presentation_ind,
+                 { "Presentation indicator", "q931.presentation_ind", FT_UINT8, BASE_HEX, VALS(q931_presentation_indicator_vals), 0x60,
+                       "", HFILL }},
+
                { &hf_q931_extension_ind,
                  { "Extension indicator",  "q931.extension_ind",
                        FT_BOOLEAN, 8, TFS(&q931_extension_ind_value), 0x80,
@@ -3079,6 +3125,8 @@ proto_register_q931(void)
        register_dissector("q931", dissect_q931, proto_q931);
        q931_tpkt_pdu_handle = create_dissector_handle(dissect_q931_tpkt_pdu,
            proto_q931);
+       register_dissector("q931.ie", dissect_q931_ie_cs0, proto_q931);
+       register_dissector("q931.ie.cs7", dissect_q931_ie_cs7, proto_q931);
 
        /* subdissector code */ 
        codeset_dissector_table = register_dissector_table("q931.codeset", "Q.931 Codeset", FT_UINT8, BASE_HEX);