bugfix to a bug reported by Ian Schorr:
[obnox/wireshark/wip.git] / packet-q931.c
index 6a76759159b48786a2dc00baaa54a1132a93a32f..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.68 2004/02/18 09:58:17 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,7 +36,9 @@
 #include <epan/strutil.h>
 #include "nlpid.h"
 #include "packet-q931.h"
+#include "packet-e164.h"
 #include "prefs.h"
+#include "reassemble.h"
 
 #include "lapd_sapi.h"
 #include "packet-tpkt.h"
@@ -64,6 +66,8 @@ static int hf_q931_call_ref_len                       = -1;
 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;
@@ -72,10 +76,46 @@ 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;
+static int hf_q931_segment_overlap = -1;
+static int hf_q931_segment_overlap_conflict = -1;
+static int hf_q931_segment_multiple_tails = -1;
+static int hf_q931_segment_too_long_segment = -1;
+static int hf_q931_segment_error = -1;
+static int hf_q931_reassembled_in = -1; 
 
 static gint ett_q931                                   = -1;
 static gint ett_q931_ie                                = -1;
 
+static gint ett_q931_segments = -1;
+static gint ett_q931_segment = -1;
+
+static const fragment_items q931_frag_items = {
+       &ett_q931_segment,
+       &ett_q931_segments,
+
+       &hf_q931_segments,
+       &hf_q931_segment,
+       &hf_q931_segment_overlap,
+       &hf_q931_segment_overlap_conflict,
+       &hf_q931_segment_multiple_tails,
+       &hf_q931_segment_too_long_segment,
+       &hf_q931_segment_error,
+       &hf_q931_reassembled_in,
+       "segments"
+};
+
+/* Tables for reassembly of fragments. */
+static GHashTable *q931_fragment_table = NULL;
+static GHashTable *q931_reassembled_table = NULL;
+
+/* Preferences */
+static gboolean q931_reassembly = TRUE;
+
 static dissector_table_t codeset_dissector_table;
 static dissector_table_t ie_dissector_table;
 
@@ -85,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.
  */
@@ -423,8 +467,7 @@ dissect_q931_segmented_message_ie(tvbuff_t *tvb, int offset, int len,
                    "Not first segment: %u segments remaining",
                    tvb_get_guint8(tvb, offset) & 0x7F);
        }
-       proto_tree_add_text(tree, tvb, offset + 1, 1,
-           "Segmented message type: %u", tvb_get_guint8(tvb, offset + 1));
+       proto_tree_add_item(tree, hf_q931_segment_type, tvb, offset + 1, 1, FALSE);
 }
 
 /*
@@ -1134,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;
@@ -1161,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;
        }
@@ -1170,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;
 
@@ -1985,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 }
 };
 
@@ -2011,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);
@@ -2029,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;
        }
@@ -2059,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);
+               }
+       }
+
 }
 
 /*
@@ -2276,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));
        }
 }
 
@@ -2285,10 +2338,18 @@ dissect_q931_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 {
        int             offset = 0;
        proto_tree      *q931_tree = NULL;
-       proto_item      *ti;
+       proto_tree      *ie_tree = NULL;
+       proto_item      *ti, *ti_ie;
        guint8          call_ref_len;
        guint8          call_ref[15];
-       guint8          message_type;
+       guint32         call_ref_val;
+       guint8          message_type, segmented_message_type;
+       guint8          info_element;
+       guint16         info_element_len;
+       gboolean        more_frags; 
+       guint32         frag_len;
+       fragment_data *fd_head;
+       tvbuff_t *next_tvb = NULL;
 
        if (check_col(pinfo->cinfo, COL_PROTOCOL))
                col_set_str(pinfo->cinfo, COL_PROTOCOL, "Q.931");
@@ -2305,6 +2366,13 @@ dissect_q931_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        if (q931_tree != NULL)
                proto_tree_add_uint(q931_tree, hf_q931_call_ref_len, tvb, offset, 1, call_ref_len);
        offset += 1;
+       switch (call_ref_len) {
+               case 0: call_ref_val = 0; break;
+               case 1: call_ref_val = tvb_get_guint8(tvb, offset);     break;
+               case 2: call_ref_val = tvb_get_ntohs(tvb, offset); break;
+               case 3: call_ref_val = tvb_get_ntoh24(tvb, offset); break;
+               default: call_ref_val = tvb_get_ntohl(tvb, offset);
+       } 
        if (call_ref_len != 0) {
                tvb_memcpy(tvb, call_ref, offset, call_ref_len);
                if (q931_tree != NULL) {
@@ -2329,7 +2397,58 @@ dissect_q931_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        /*
         * And now for the information elements....
         */
-       dissect_q931_IEs(tvb, pinfo, tree, q931_tree,is_tpkt, offset);
+       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, 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, 0);
+               return;
+       }
+       /* Segmented message IE */
+       ti_ie = proto_tree_add_text(q931_tree, tvb, offset, 1+1+info_element_len, "%s",
+                                   val_to_str(info_element, q931_info_element_vals[0], "Unknown information element (0x%02X)"));
+       ie_tree = proto_item_add_subtree(ti_ie, ett_q931_ie);
+       proto_tree_add_text(ie_tree, tvb, offset, 1, "Information element: %s",
+                                   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;
+       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);
+       fd_head = fragment_add_seq_next(tvb, offset, pinfo, call_ref_val,
+                                                                       q931_fragment_table, q931_reassembled_table,
+                                                                       frag_len, more_frags);
+       if (fd_head) {
+               if (pinfo->fd->num == fd_head->reassembled_in) {  /* last fragment */
+                       if (fd_head->next != NULL) {  /* 2 or more segments */
+                               next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
+                               tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+                               add_new_data_source(pinfo, next_tvb, "Reassembled Q.931 IEs");
+                               /* Show all fragments. */
+                               if (tree) show_fragment_seq_tree(fd_head, &q931_frag_items, q931_tree, pinfo, next_tvb);
+                       } else {  /* only 1 segment */
+                               next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+                       }
+                       if (check_col(pinfo->cinfo, COL_INFO)) {
+                               col_add_fstr(pinfo->cinfo, COL_INFO, "%s [reassembled]",
+                                   val_to_str(segmented_message_type, q931_message_type_vals, "Unknown message type (0x%02X)"));
+                       }
+               } else {
+                       if (tree) proto_tree_add_uint(q931_tree, hf_q931_reassembled_in, tvb, offset, frag_len, fd_head->reassembled_in);
+               }
+       }
+       if (next_tvb)
+               dissect_q931_IEs(next_tvb, pinfo, tree, q931_tree, is_tpkt, 0, 0);
 }
 
 static const value_string q931_codeset_vals[] = {
@@ -2341,20 +2460,23 @@ 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;
        guint8          info_element;
        guint16         info_element_len;
        int             codeset, locked_codeset;
-       gboolean        non_locking_shift;
+       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) {
                info_element = tvb_get_guint8(tvb, offset);
 
@@ -2509,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
@@ -2527,6 +2649,11 @@ dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                } else {
                        info_element_len = tvb_get_guint8(tvb, offset + 1);
 
+                       if (first_segment && (tvb_reported_length_remaining(tvb, offset + 2) < info_element_len)) {  /* incomplete IE at the end of the 1st segment */
+                               proto_tree_add_text(q931_tree, tvb, offset, tvb_reported_length_remaining(tvb, offset), "Incomplete IE in the 1st segment");
+                               break;
+                       }
+
                        /*
                         * Check for subdissectors for this IE or
                         * for all IEs in this codeset.
@@ -2542,27 +2669,28 @@ dissect_q931_IEs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                }
                        }
 
-                       if (q931_tree != NULL) {
-                               ti = proto_tree_add_text(q931_tree, tvb, offset,
-                                   1+1+info_element_len, "%s",
-                                   val_to_str(info_element, q931_info_element_vals[codeset],
-                                     "Unknown information element (0x%02X)"));
-                                       ie_tree = proto_item_add_subtree(ti, ett_q931_ie);
-                               proto_tree_add_text(ie_tree, tvb, offset, 1,
-                                   "Information element: %s",
-                                   val_to_str(info_element, q931_info_element_vals[codeset],
-                                     "Unknown (0x%02X)"));
-                               proto_tree_add_text(ie_tree, tvb, offset + 1, 1,
-                                   "Length: %u", info_element_len);
-
+                       ti = proto_tree_add_text(q931_tree, tvb, offset, 1+1+info_element_len, "%s",
+                                   val_to_str(info_element, q931_info_element_vals[codeset], "Unknown information element (0x%02X)"));
+                       ie_tree = proto_item_add_subtree(ti, ett_q931_ie);
+                       proto_tree_add_text(ie_tree, tvb, offset, 1, "Information element: %s",
+                                   val_to_str(info_element, q931_info_element_vals[codeset], "Unknown (0x%02X)"));
+                       proto_tree_add_text(ie_tree, tvb, offset + 1, 1, "Length: %u", info_element_len);
+
+                       if (((codeset << 8) | info_element) == (CS0 | Q931_IE_SEGMENTED_MESSAGE)) {
+                               dissect_q931_segmented_message_ie(tvb, offset + 2, info_element_len, ie_tree);
+                               if (check_col(pinfo->cinfo, COL_INFO)) {
+                                       col_append_fstr(pinfo->cinfo, COL_INFO, " of %s",
+                                           val_to_str(tvb_get_guint8(tvb, offset + 3), q931_message_type_vals, "Unknown message type (0x%02X)"));
+                               }
+                               if (tvb_get_guint8(tvb, offset + 2) & 0x80) {  /* the 1st segment */
+                                       first_segment = TRUE;
+                               } else {  /* not the 1st segment */
+                                       proto_tree_add_text(q931_tree, tvb, offset + 4, tvb_reported_length_remaining(tvb, offset + 4), "Message segment");
+                                       info_element_len += tvb_reported_length_remaining(tvb, offset + 4);
+                               }
+                       } else if (q931_tree != NULL) {
                                switch ((codeset << 8) | info_element) {
 
-                               case CS0 | Q931_IE_SEGMENTED_MESSAGE:
-                                       dissect_q931_segmented_message_ie(tvb,
-                                           offset + 2, info_element_len,
-                                           ie_tree);
-                                       break;
-
                                case CS0 | Q931_IE_BEARER_CAPABILITY:
                                case CS0 | Q931_IE_LOW_LAYER_COMPAT:
                                        dissect_q931_bearer_capability_ie(tvb,
@@ -2681,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:
@@ -2835,6 +2965,25 @@ 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 */
+       fragment_table_init(&q931_fragment_table);
+       reassembled_table_init(&q931_reassembled_table);
+}
+
 void
 proto_register_q931(void)
 {
@@ -2843,6 +2992,10 @@ proto_register_q931(void)
                  { "Protocol discriminator", "q931.disc", FT_UINT8, BASE_HEX, NULL, 0x0,
                        "", HFILL }},
 
+               { &hf_q931_call_ref_len,
+                 { "Call reference value length", "q931.call_ref_len", FT_UINT8, BASE_DEC, NULL, 0x0,
+                       "", HFILL }},
+
                { &hf_q931_call_ref_flag,
                  { "Call reference flag", "q931.call_ref_flag", FT_BOOLEAN, BASE_NONE, TFS(&tfs_call_ref_flag), 0x0,
                        "", HFILL }},
@@ -2851,6 +3004,13 @@ proto_register_q931(void)
                  { "Call reference value", "q931.call_ref", FT_BYTES, BASE_HEX, NULL, 0x0,
                        "", HFILL }},
 
+               { &hf_q931_message_type,
+                 { "Message type", "q931.message_type", FT_UINT8, BASE_HEX, VALS(q931_message_type_vals), 0x0,
+                       "", HFILL }},
+
+               { &hf_q931_segment_type,
+                 { "Segmented message type", "q931.segment_type", FT_UINT8, BASE_HEX, VALS(q931_message_type_vals), 0x0,
+                       "", HFILL }},
 
                { &hf_q931_coding_standard,
                  { "Coding standard", "q931.coding_standard", FT_UINT8, BASE_HEX,
@@ -2872,16 +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_call_ref_len,
-                 { "Call reference value length", "q931.call_ref_len", FT_UINT8, BASE_DEC, NULL, 0x0,
-                       "", HFILL }},
-
-               { &hf_q931_message_type,
-                 { "Message type", "q931.message_type", FT_UINT8, BASE_HEX, VALS(q931_message_type_vals), 0x0,
+               { &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,
@@ -2892,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,
@@ -2912,20 +3076,57 @@ proto_register_q931(void)
                { &hf_q931_redirecting_number,
                  { "Redirecting party number digits", "q931.redirecting_number.digits", FT_STRING, BASE_NONE, NULL, 0x0,
                        "", HFILL }},
+    /* desegmentation fields */
+               { &hf_q931_segment_overlap,
+                 { "Segment overlap", "q931.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                       "Fragment overlaps with other fragments", HFILL }},
+
+               { &hf_q931_segment_overlap_conflict,
+                 { "Conflicting data in fragment overlap", "q931.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                       "Overlapping fragments contained conflicting data", HFILL }},
+
+               { &hf_q931_segment_multiple_tails,
+                 { "Multiple tail fragments found", "q931.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                       "Several tails were found when defragmenting the packet", HFILL }},
+
+               { &hf_q931_segment_too_long_segment,
+                 { "Segment too long", "q931.segment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                       "Segment contained data past end of packet", HFILL }},
+
+               { &hf_q931_segment_error,
+                 { "Defragmentation error", "q931.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+                       "Defragmentation error due to illegal fragments", HFILL }},
+
+               { &hf_q931_segment,
+                 { "Q.931 Segment", "q931.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+                       "Q.931 Segment", HFILL }},
+
+               { &hf_q931_segments,
+                 { "Q.931 Segments", "q931.segments", FT_NONE, BASE_NONE, NULL, 0x0,
+                       "Q.931 Segments", HFILL }},
+
+               { &hf_q931_reassembled_in,
+                 { "Reassembled Q.931 in frame", "q931.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+                       "This Q.931 message is reassembled in this frame", HFILL}}, 
        };
        static gint *ett[] = {
                &ett_q931,
                &ett_q931_ie,
+               &ett_q931_segments,
+               &ett_q931_segment,
        };
        module_t *q931_module;
 
        proto_q931 = proto_register_protocol("Q.931", "Q.931", "q931");
        proto_register_field_array (proto_q931, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
+       register_init_routine(q931_init);
 
        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);
@@ -2936,6 +3137,10 @@ proto_register_q931(void)
            "Desegment all Q.931 messages spanning multiple TCP segments",
            "Whether the Q.931 dissector should desegment all messages spanning multiple TCP segments",
            &q931_desegment);
+       prefs_register_bool_preference(q931_module, "reassembly",
+           "Reassemble segmented Q.931 messages",
+           "Reassemble segmented Q.931 messages (Q.931 - Annex H)",
+           &q931_reassembly);
 }
 
 void