Q.933 dissector. (Not complete.)
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 3 Sep 2003 05:39:21 +0000 (05:39 +0000)
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 3 Sep 2003 05:39:21 +0000 (05:39 +0000)
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@8350 f5534014-38df-0310-8fa8-9805f1628bb7

Makefile.am
Makefile.nmake
nlpid.h
packet-fr.c
packet-q933.c [new file with mode: 0644]

index bd519c35916d00df7b21b0daf0bbc2ca5dfd6ece..f0ba7d9692aada849509ec59030534a3cd02dd9e 100644 (file)
@@ -1,7 +1,7 @@
 # Makefile.am
 # Automake file for Ethereal
 #
-# $Id: Makefile.am,v 1.617 2003/09/02 22:47:56 guy Exp $
+# $Id: Makefile.am,v 1.618 2003/09/03 05:39:21 guy Exp $
 #
 # Ethereal - Network traffic analyzer
 # By Gerald Combs <gerald@ethereal.com>
@@ -330,6 +330,7 @@ DISSECTOR_SRC = \
        packet-prism.c \
        packet-q2931.c \
        packet-q931.c  \
+       packet-q933.c  \
        packet-qllc.c  \
        packet-quake.c \
        packet-quake2.c \
index 6d0cb72dba0f4abaf76766a5b99264164d93473c..e7e603759f55111ac26cf5cb4565e90e29683650 100644 (file)
@@ -1,7 +1,7 @@
 ## Makefile for building ethereal.exe with Microsoft C and nmake
 ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
 #
-# $Id: Makefile.nmake,v 1.330 2003/09/02 22:47:56 guy Exp $
+# $Id: Makefile.nmake,v 1.331 2003/09/03 05:39:21 guy Exp $
 
 include config.nmake
 include <win32.mak>
@@ -271,6 +271,7 @@ DISSECTOR_SRC = \
        packet-prism.c \
        packet-q2931.c \
        packet-q931.c  \
+       packet-q933.c  \
        packet-qllc.c  \
        packet-quake.c \
        packet-quake2.c \
diff --git a/nlpid.h b/nlpid.h
index bf1127f5a744dcc2d435123028e2c4bc1196ef1e..66347e16f7c74626e3d1decc3d79280c1ae23a54 100644 (file)
--- a/nlpid.h
+++ b/nlpid.h
@@ -2,7 +2,7 @@
  * Definitions of OSI NLPIDs (Network Layer Protocol IDs)
  * Laurent Deniel <laurent.deniel@free.fr>
  *
- * $Id: nlpid.h,v 1.13 2003/02/24 19:49:03 guy Exp $
+ * $Id: nlpid.h,v 1.14 2003/09/03 05:39:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -32,7 +32,8 @@
 #define NLPID_IPI_T_70         0x01    /* T.70, when an IPI */
 #define NLPID_SPI_X_29         0x01    /* X.29, when an SPI */
 #define NLPID_X_633            0x03    /* X.633 */
-#define NLPID_Q_931            0x08    /* Q.931, Q.932, Q.933, X.36, ISO 11572, ISO 11582 */
+#define NLPID_Q_931            0x08    /* Q.931, Q.932, X.36, ISO 11572, ISO 11582 */
+#define NLPID_Q_933            0x08    /* Q.933, on Frame Relay */
 #define NLPID_Q_2931           0x09    /* Q.2931 */
 #define NLPID_Q_2119           0x0c    /* Q.2119 */
 #define NLPID_SNAP             0x80
index 26bf73e3152cf26aff718aed3a8cf4e0a215a068..1271f302a9fa1f01729bac2d8ebf85bc5a1855f2 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2001, Paul Ionescu        <paul@acorp.ro>
  *
- * $Id: packet-fr.c,v 1.40 2003/09/02 23:42:01 guy Exp $
+ * $Id: packet-fr.c,v 1.41 2003/09/03 05:39:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -142,6 +142,7 @@ static const value_string fr_nlpid_vals[] = {
 };
 
 static dissector_table_t fr_subdissector_table;
+static dissector_table_t fr_osinl_subdissector_table;
 
 static void dissect_fr_nlpid(tvbuff_t *tvb, int offset, packet_info *pinfo,
                             proto_tree *tree, proto_item *ti,
@@ -411,9 +412,15 @@ static void dissect_fr_nlpid(tvbuff_t *tvb, int offset, packet_info *pinfo,
    * OSI network layer protocols consider the NLPID to be part
    * of the frame, so we'll pass it as part of the payload and,
    * if the protocol is one of those, add it as a hidden item here.
+   * We check both the generic OSI NLPID dissector table and
+   * the Frame Relay OSI NLPID dissector table - the latter is for
+   * NLPID's such as 0x08, which is Q.933 in Frame Relay but
+   * other protocols (e.g., Q.931) on other network layers.
    */
   next_tvb = tvb_new_subset(tvb,offset,-1,-1);
   if (dissector_try_port(osinl_subdissector_table, fr_nlpid, next_tvb,
+                        pinfo, tree) ||
+      dissector_try_port(fr_osinl_subdissector_table, fr_nlpid, next_tvb,
                         pinfo, tree)) {
        /*
         * Yes, we got a match.  Add the NLPID as a hidden item,
@@ -575,6 +582,8 @@ void proto_register_fr(void)
 
   fr_subdissector_table = register_dissector_table("fr.ietf",
        "Frame Relay NLPID", FT_UINT8, BASE_HEX);
+  fr_osinl_subdissector_table = register_dissector_table("fr.osinl",
+       "Frame Relay OSI NLPID", FT_UINT8, BASE_HEX);
 
   register_dissector("fr_uncompressed", dissect_fr_uncompressed, proto_fr);
   register_dissector("fr", dissect_fr, proto_fr);
diff --git a/packet-q933.c b/packet-q933.c
new file mode 100644 (file)
index 0000000..eb7ef0e
--- /dev/null
@@ -0,0 +1,2173 @@
+/* packet-q933.c
+ * Routines for Q.933 frame disassembly
+ * Guy Harris <guy@alum.mit.edu>
+ *
+ * $Id: packet-q933.c,v 1.1 2003/09/03 05:39:21 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+#include <epan/packet.h>
+#include <epan/strutil.h>
+#include "nlpid.h"
+#include "prefs.h"
+
+#include "packet-tpkt.h"
+
+static int proto_q933 = -1;
+static int hf_q933_discriminator = -1;
+static int hf_q933_call_ref_len = -1;
+static int hf_q933_call_ref_flag = -1;
+static int hf_q933_call_ref = -1;
+static int hf_q933_message_type = -1;
+static int hf_q933_cause_value = -1;
+static int hf_q933_calling_party_number = -1;
+static int hf_q933_called_party_number = -1;
+static int hf_q933_connected_number = -1;
+static int hf_q933_redirecting_number = -1;
+
+static gint ett_q933 = -1;
+static gint ett_q933_ie = -1;
+
+/*
+ * Q.933 message types.
+ */
+#define        Q933_ESCAPE             0x00
+#define        Q933_ALERTING           0x01
+#define        Q933_CALL_PROCEEDING    0x02
+#define        Q933_CONNECT            0x07
+#define        Q933_CONNECT_ACK        0x0F
+#define        Q933_PROGRESS           0x03
+#define        Q933_SETUP              0x05
+#define        Q933_DISCONNECT         0x45
+#define        Q933_RELEASE            0x4D
+#define        Q933_RELEASE_COMPLETE   0x5A
+#define        Q933_SEGMENT            0x60
+#define        Q933_STATUS             0x7D
+#define        Q933_STATUS_ENQUIRY     0x75
+
+static const value_string q933_message_type_vals[] = {
+       { Q933_ESCAPE,                  "ESCAPE" },
+       { Q933_ALERTING,                "ALERTING" },
+       { Q933_CALL_PROCEEDING,         "CALL PROCEEDING" },
+       { Q933_CONNECT,                 "CONNECT" },
+       { Q933_CONNECT_ACK,             "CONNECT ACKNOWLEDGE" },
+       { Q933_PROGRESS,                "PROGRESS" },
+       { Q933_SETUP,                   "SETUP" },
+       { Q933_DISCONNECT,              "DISCONNECT" },
+       { Q933_RELEASE,                 "RELEASE" },
+       { Q933_RELEASE_COMPLETE,        "RELEASE COMPLETE" },
+       { Q933_SEGMENT,                 "SEGMENT" },
+       { Q933_STATUS,                  "STATUS" },
+       { Q933_STATUS_ENQUIRY,          "STATUS ENQUIRY" },
+       { 0,                            NULL }
+};
+
+static const true_false_string tfs_call_ref_flag = {
+       "Message sent to originating side",
+       "Message sent from originating side"
+};
+
+/*
+ * Information elements.
+ */
+
+/* Shifted codeset values */
+#define CS0 0x000
+#define CS1 0x100
+#define CS2 0x200
+#define CS3 0x300
+#define CS4 0x400
+#define CS5 0x500
+#define CS6 0x600
+#define CS7 0x700
+
+#define        Q933_IE_SO_MASK 0x80    /* single-octet/variable-length mask */
+/*
+ * Single-octet IEs.
+ */
+#define        Q933_IE_SO_IDENTIFIER_MASK      0xf0    /* IE identifier mask */
+#define        Q933_IE_SO_IDENTIFIER_SHIFT     4       /* IE identifier shift */
+#define        Q933_IE_SO_IE_MASK              0x0F    /* IE mask */
+
+#define        Q933_IE_SHIFT                   0x90
+#define        Q933_IE_SHIFT_NON_LOCKING       0x08    /* non-locking shift */
+#define        Q933_IE_SHIFT_CODESET           0x0F    /* codeset */
+
+#define        Q933_IE_REPEAT_INDICATOR        0xD0
+
+/*
+ * Variable-length IEs.
+ */
+#define        Q933_IE_VL_EXTENSION            0x80    /* Extension flag */
+
+/*
+ * Codeset 0 (default).
+ */
+#define        Q933_IE_SEGMENTED_MESSAGE       0x00
+#define        Q933_IE_BEARER_CAPABILITY       0x04
+#define        Q933_IE_CAUSE                   0x08
+#define        Q933_IE_CALL_STATE              0x14
+#define        Q933_IE_CHANNEL_IDENTIFICATION  0x18
+#define        Q933_IE_DLCI                    0x19
+#define        Q933_IE_PROGRESS_INDICATOR      0x1E
+#define        Q933_IE_NETWORK_SPECIFIC_FACIL  0x20    /* Network Specific Facilities */
+#define        Q933_IE_DISPLAY                 0x28
+#define        Q933_IE_E2E_TRANSIT_DELAY       0x42    /* End-to-end Transit Delay */
+#define        Q933_IE_TD_SELECTION_AND_INT    0x43    /* Transit Delay Selection and Indication */
+#define        Q933_IE_PL_BINARY_PARAMETERS    0x44    /* Packet layer binary parameters */
+#define        Q933_IE_LL_CORE_PARAMETERS      0x48    /* Link layer core parameters */
+#define        Q933_IE_LL_PROTOCOL_PARAMETERS  0x49    /* Link layer protocol parameters */
+#define        Q933_IE_REVERSE_CHARGE_IND      0x4A    /* Reverse charging indication */
+#define        Q933_IE_CONNECTED_NUMBER        0x4C    /* Connected Number */
+#define        Q933_IE_CONNECTED_SUBADDR       0x4D    /* Connected sub-address */
+#define        Q933_IE_X_213_PRIORITY          0x50    /* X.213 priority */
+#define        Q933_IE_REPORT_TYPE             0x51
+#define        Q933_IE_LINK_INTEGRITY_VERF     0x53    /* Link integrity verification */
+#define        Q933_IE_PVC_STATUS              0x57
+#define        Q933_IE_CALLING_PARTY_NUMBER    0x6C    /* Calling Party Number */
+#define        Q933_IE_CALLING_PARTY_SUBADDR   0x6D    /* Calling Party Subaddress */
+#define        Q933_IE_CALLED_PARTY_NUMBER     0x70    /* Called Party Number */
+#define        Q933_IE_CALLED_PARTY_SUBADDR    0x71    /* Called Party Subaddress */
+#define        Q933_IE_TRANSIT_NETWORK_SEL     0x78    /* Transit Network Selection */
+#define        Q933_IE_LOW_LAYER_COMPAT        0x7C    /* Low-Layer Compatibility */
+#define        Q933_IE_HIGH_LAYER_COMPAT       0x7D    /* High-Layer Compatibility */
+#define        Q933_IE_USER_USER               0x7E    /* User-User */
+#define        Q933_IE_ESCAPE                  0x7F    /* Escape for extension */
+
+/* Codeset 0 */
+static const value_string q933_info_element_vals0[] = {
+       { Q933_IE_SEGMENTED_MESSAGE,            "Segmented message" },
+       { Q933_IE_BEARER_CAPABILITY,            "Bearer capability" },
+       { Q933_IE_CAUSE,                        "Cause" },
+       { Q933_IE_CALL_STATE,                   "Call state" },
+       { Q933_IE_CHANNEL_IDENTIFICATION,       "Channel identification" },
+       { Q933_IE_DLCI,                         "Data link connection identifier" },
+       { Q933_IE_PROGRESS_INDICATOR,           "Progress indicator" },
+       { Q933_IE_NETWORK_SPECIFIC_FACIL,       "Network specific facilities" },
+       { Q933_IE_E2E_TRANSIT_DELAY,            "End-to-end transit delay" },
+       { Q933_IE_TD_SELECTION_AND_INT,         "Transit delay selection and indication" },
+       { Q933_IE_PL_BINARY_PARAMETERS,         "Packet layer binary parameters" },
+       { Q933_IE_LL_CORE_PARAMETERS,           "Link layer core parameters" },
+       { Q933_IE_LL_PROTOCOL_PARAMETERS,       "Link layer protocol parameters" },
+       { Q933_IE_REVERSE_CHARGE_IND,           "Reverse charging indication" },
+       { Q933_IE_CONNECTED_NUMBER,             "Connected number" },
+       { Q933_IE_CONNECTED_SUBADDR,            "Connected subaddress" },
+       { Q933_IE_X_213_PRIORITY,               "X.213 priority" },
+       { Q933_IE_REPORT_TYPE,                  "Report type" },
+       { Q933_IE_LINK_INTEGRITY_VERF,          "Link integrity verification" },
+       { Q933_IE_PVC_STATUS,                   "PVC status" },
+       { Q933_IE_CALLING_PARTY_NUMBER,         "Calling party number" },
+       { Q933_IE_CALLING_PARTY_SUBADDR,        "Calling party subaddress" },
+       { Q933_IE_CALLED_PARTY_NUMBER,          "Called party number" },
+       { Q933_IE_CALLED_PARTY_SUBADDR,         "Called party subaddress" },
+       { Q933_IE_TRANSIT_NETWORK_SEL,          "Transit network selection" },
+       { Q933_IE_LOW_LAYER_COMPAT,             "Low-layer compatibility" },
+       { Q933_IE_HIGH_LAYER_COMPAT,            "High-layer compatibility" },
+       { Q933_IE_USER_USER,                    "User-user" },
+       { Q933_IE_ESCAPE,                       "Escape" },
+       { 0,                                    NULL }
+};
+/* Codeset 1 */
+static const value_string q933_info_element_vals1[] = {
+       { 0,                                    NULL }
+};
+/* Codeset 2 */
+static const value_string q933_info_element_vals2[] = {
+       { 0,                                    NULL }
+};
+/* Codeset 3 */
+static const value_string q933_info_element_vals3[] = {
+       { 0,                                    NULL }
+};
+/* Codeset 4 */
+static const value_string q933_info_element_vals4[] = {
+       { 0,                                    NULL }
+};
+/* Codeset 5 */
+static const value_string q933_info_element_vals5[] = {
+       { 0,                                    NULL }
+};
+/* Codeset 6 */
+static const value_string q933_info_element_vals6[] = {
+       { 0,                                    NULL }
+};
+/* Codeset 7 */
+static const value_string q933_info_element_vals7[] = {
+       { 0,                                    NULL }
+};
+
+/* Codeset array */
+static const value_string *q933_info_element_vals[] = {
+  q933_info_element_vals0,
+  q933_info_element_vals1,
+  q933_info_element_vals2,
+  q933_info_element_vals3,
+  q933_info_element_vals4,
+  q933_info_element_vals5,
+  q933_info_element_vals6,
+  q933_info_element_vals7,
+};
+
+static const value_string q933_congestion_level_vals[] = {
+       { 0x0, "Receiver ready" },
+       { 0xF, "Receiver not ready" },
+       { 0,   NULL }
+};
+
+static const value_string q933_repeat_indication_vals[] = {
+       { 0x2, "Prioritized list" },
+       { 0,   NULL }
+};
+
+/*
+ * ITU-standardized coding.
+ */
+#define        Q933_ITU_STANDARDIZED_CODING    0x00
+
+/*
+ * Dissect a Segmented message information element.
+ */
+static void
+dissect_q933_segmented_message_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       if (len != 2) {
+               proto_tree_add_text(tree, tvb, offset, len,
+                   "Segmented message: length is %d, should be 2\n", len);
+               return;
+       }
+       if (tvb_get_guint8(tvb, offset) & 0x80) {
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "First segment: %u segments remaining",
+                   tvb_get_guint8(tvb, offset) & 0x7F);
+       } else {
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "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\n", tvb_get_guint8(tvb, offset + 1));
+}
+
+/*
+ * Dissect a Bearer capability or Low-layer compatibility information element.
+ */
+static const value_string q933_bc_coding_standard_vals[] = {
+       { 0x00, "ITU-T standardized coding" },
+       { 0x20, "ISO/IEC standard" },
+       { 0x40, "National standard" },
+       { 0x60, "Standard defined for this particular network" },
+       { 0,    NULL }
+};
+
+static const value_string q933_information_transfer_capability_vals[] = {
+       { 0x08, "Unrestricted digital information" },
+       { 0,    NULL }
+};
+
+static const value_string q933_transfer_mode_vals[] = {
+       { 0x20, "Frame mode" },
+       { 0,    NULL }
+};
+
+#define        Q933_IT_RATE_MULTIRATE  0x18
+
+static const value_string q933_information_transfer_rate_vals[] = {
+       { 0x00,                         "Packet mode" },
+       { 0x10,                         "64 kbit/s" },
+       { 0x11,                         "2 x 64 kbit/s" },
+       { 0x13,                         "384 kbit/s" },
+       { 0x15,                         "1536 kbit/s" },
+       { 0x17,                         "1920 kbit/s" },
+       { Q933_IT_RATE_MULTIRATE,       "Multirate (64 kbit/s base rate)" },
+       { 0,                            NULL }
+};
+
+static const value_string q933_uil1_vals[] = {
+       { 0x01, "V.110/I.460/X.30 rate adaption" },
+       { 0x02, "Recommendation G.711 u-law" },
+       { 0x03, "Recommendation G.711 A-law" },
+       { 0x04, "Recommendation G.721 32 kbit/s ADPCM and Recommendation I.460" },
+       { 0x05, "Recommendation H.221 and H.242" },
+       { 0x06, "Recommendation H.223 and H.245" },
+       { 0x07, "Non-ITU-T-standardized rate adaption" },
+       { 0x08, "V.120 rate adaption" },
+       { 0x09, "X.31 HDLC flag stuffing" },
+       { 0,    NULL },
+};
+
+static const value_string q933_l1_user_rate_vals[] = {
+       { 0x00, "Rate indicated by E-bits" },
+       { 0x01, "0.6 kbit/s" },
+       { 0x02, "1.2 kbit/s" },
+       { 0x03, "2.4 kbit/s" },
+       { 0x04, "3.6 kbit/s" },
+       { 0x05, "4.8 kbit/s" },
+       { 0x06, "7.2 kbit/s" },
+       { 0x07, "8 kbit/s" },
+       { 0x08, "9.6 kbit/s" },
+       { 0x09, "14.4 kbit/s" },
+       { 0x0A, "16 kbit/s" },
+       { 0x0B, "19.2 kbit/s" },
+       { 0x0C, "32 kbit/s" },
+       { 0x0E, "48 kbit/s" },
+       { 0x0F, "56 kbit/s" },
+       { 0x10, "64 kbit/s "},
+       { 0x15, "0.1345 kbit/s" },
+       { 0x16, "0.100 kbit/s" },
+       { 0x17, "0.075/1.2 kbit/s" },
+       { 0x18, "1.2/0.075 kbit/s" },
+       { 0x19, "0.050 kbit/s" },
+       { 0x1A, "0.075 kbit/s" },
+       { 0x1B, "0.110 kbit/s" },
+       { 0x1C, "0.150 kbit/s" },
+       { 0x1D, "0.200 kbit/s" },
+       { 0x1E, "0.300 kbit/s" },
+       { 0x1F, "12 kbit/s" },
+       { 0,    NULL }
+};
+
+static const value_string q933_l1_intermediate_rate_vals[] = {
+       { 0x20, "8 kbit/s" },
+       { 0x40, "16 kbit/s" },
+       { 0x60, "32 kbit/s" },
+       { 0,    NULL }
+};
+
+static const value_string q933_l1_stop_bits_vals[] = {
+       { 0x20, "1" },
+       { 0x40, "1.5" },
+       { 0x60, "2" },
+       { 0,    NULL }
+};
+
+static const value_string q933_l1_data_bits_vals[] = {
+       { 0x08, "5" },
+       { 0x10, "7" },
+       { 0x18, "8" },
+       { 0,    NULL }
+};
+
+static const value_string q933_l1_parity_vals[] = {
+       { 0x00, "Odd" },
+       { 0x02, "Even" },
+       { 0x03, "None" },
+       { 0x04, "Forced to 0" },
+       { 0x05, "Forced to 1" },
+       { 0,    NULL }
+};
+
+static const value_string q933_l1_modem_type_vals[] = {
+       { 0x11, "V.21" },
+       { 0x12, "V.22" },
+       { 0x13, "V.22 bis" },
+       { 0x14, "V.23" },
+       { 0x15, "V.26" },
+       { 0x16, "V.26 bis" },
+       { 0x17, "V.26 ter" },
+       { 0x18, "V.27" },
+       { 0x19, "V.27 bis" },
+       { 0x1A, "V.27 ter" },
+       { 0x1B, "V.29" },
+       { 0x1C, "V.32" },
+       { 0x1E, "V.34" },
+       { 0,    NULL }
+};
+
+#define        Q933_UIL2_USER_SPEC     0x10
+
+static const value_string q933_uil2_vals[] = {
+       { 0x01,                 "Basic mode ISO 1745" },
+       { 0x06,                 "X.25, link level" },
+       { 0x07,                 "X.25 multilink" },
+       { 0x08,                 "T.71 Extended LAPB" },
+       { 0x09,                 "HDLC ARM" },
+       { 0x0A,                 "HDLC NRM" },
+       { 0x0B,                 "HDLC ABM" },
+       { 0x0C,                 "ISO 8802/2 LLC" },
+       { 0x0D,                 "X.75 Single Link Procedure" },
+       { 0x0E,                 "Q.922" },
+       { 0x0F,                 "Core aspects of Q.922" },
+       { Q933_UIL2_USER_SPEC,  "User-specified" },
+       { 0x11,                 "ISO 7776 DTE-DTE operation" },
+       { 0,                    NULL }
+};
+
+static const value_string q933_address_inclusion_vals[] = {
+       { 0x01,                 "Address included" },
+       { 0x02,                 "Encapsulation of logical control frame" },
+       { 0,                    NULL }
+};
+
+static const value_string q933_mode_vals[] = {
+       { 0x20, "Normal mode" },
+       { 0x40, "Extended mode" },
+       { 0,    NULL }
+};
+
+#define        Q933_UIL3_X25_PL        0x06
+#define        Q933_UIL3_ISO_8208      0x07    /* X.25-based */
+#define        Q933_UIL3_X223          0x08    /* X.25-based */
+#define        Q933_UIL3_TR_9577       0x0B
+#define        Q933_UIL3_USER_SPEC     0x10
+
+static const value_string q933_uil3_vals[] = {
+       { Q933_UIL3_X25_PL,     "X.25, packet layer" },
+       { Q933_UIL3_ISO_8208,   "ISO/IEC 8208" },
+       { Q933_UIL3_X223,       "X.223/ISO 8878" },
+       { 0x09,                 "ISO/IEC 8473" },
+       { 0x0A,                 "T.70" },
+       { Q933_UIL3_TR_9577,    "ISO/IEC TR 9577" },
+       { Q933_UIL3_USER_SPEC,  "User-specified" },
+       { 0,                    NULL }
+};
+
+static void
+dissect_q933_protocol_discriminator(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+       unsigned int discriminator = tvb_get_guint8(tvb, offset);
+
+       if (discriminator == NLPID_Q_933) {
+               proto_tree_add_uint_format(tree, hf_q933_discriminator,
+                        tvb, offset, 1, discriminator,
+                        "Protocol discriminator: Q.933");
+       } else if (discriminator == NLPID_Q_2931) {
+               proto_tree_add_uint_format(tree, hf_q933_discriminator,
+                        tvb, offset, 1, discriminator,
+                        "Protocol discriminator: Q.2931");
+       } else if ((discriminator >= 16 && discriminator < 63)
+           || ((discriminator >= 80) && (discriminator < 254))) {
+               proto_tree_add_uint_format(tree, hf_q933_discriminator,
+                   tvb, offset, 1, discriminator,
+                   "Protocol discriminator: Network layer or layer 3 protocol (0x%02X)",
+                   discriminator);
+       } else if (discriminator >= 64 && discriminator <= 79) {
+               proto_tree_add_uint_format(tree, hf_q933_discriminator,
+                   tvb, offset, 1, discriminator,
+                   "Protocol discriminator: National use (0x%02X)",
+                   discriminator);
+       } else {
+               proto_tree_add_uint_format(tree, hf_q933_discriminator,
+                   tvb, offset, 1, discriminator,
+                   "Protocol discriminator: Reserved (0x%02X)",
+                   discriminator);
+       }
+}
+
+void
+dissect_q933_bearer_capability_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+       guint8 coding_standard;
+       guint8 modem_type;
+       guint8 uil2_protocol;
+       guint8 uil3_protocol;
+       guint8 add_l3_info;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       coding_standard = octet & 0x60;
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Coding standard: %s",
+           val_to_str(coding_standard, q933_bc_coding_standard_vals, NULL));
+       if (coding_standard != Q933_ITU_STANDARDIZED_CODING) {
+               /*
+                * We don't know how the bearer capability is encoded,
+                * so just dump it as data and be done with it.
+                */
+               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,
+           "Information transfer capability: %s",
+           val_to_str(octet & 0x1F, q933_information_transfer_capability_vals,
+             "Unknown (0x%02X)"));
+       offset += 1;
+       len -= 1;
+
+       /*
+        * XXX - only in Low-layer compatibility information element.
+        */
+       if (!(octet & Q933_IE_VL_EXTENSION)) {
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Out-band negotiation %spossible",
+                   (octet & 0x40) ? "" : "not ");
+               offset += 1;
+               len -= 1;
+       }
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Transfer mode: %s",
+           val_to_str(octet & 0x60, q933_transfer_mode_vals,
+             "Unknown (0x%02X)"));
+       offset += 1;
+       len -= 1;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       if ((octet & 0x60) == 0x20) {
+               /*
+                * Layer 1 information.
+                */
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "User information layer 1 protocol: %s",
+                   val_to_str(octet & 0x1F, q933_uil1_vals,
+                     "Unknown (0x%02X)"));
+               offset += 1;
+               len -= 1;
+
+               if (octet & Q933_IE_VL_EXTENSION)
+                       goto l1_done;
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Layer 1 is %s",
+                   (octet & 0x40) ? "Asynchronous" : "Synchronous");
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "User rate: %s",
+                   val_to_str(octet & 0x1F, q933_l1_user_rate_vals,
+                     "Unknown (0x%02X)"));
+               offset += 1;
+               len -= 1;
+
+               if (octet & Q933_IE_VL_EXTENSION)
+                       goto l1_done;
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Rate adaption header %sincluded",
+                   (octet & 0x40) ? "" : "not ");
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Multiple frame establishment %ssupported",
+                   (octet & 0x20) ? "" : "not ");
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "%s mode of operation",
+                   (octet & 0x10) ? "Protocol sensitive" : "Bit transparent");
+               offset += 1;
+               len -= 1;
+
+               if (octet & Q933_IE_VL_EXTENSION)
+                       goto l1_done;
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Stop bits: %s",
+                     val_to_str(octet & 0x60, q933_l1_stop_bits_vals,
+                      "Unknown (0x%X)"));
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Data bits: %s",
+                     val_to_str(octet & 0x18, q933_l1_data_bits_vals,
+                      "Unknown (0x%X)"));
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Parity: %s",
+                     val_to_str(octet & 0x07, q933_l1_parity_vals,
+                      "Unknown (0x%X)"));
+
+               if (octet & Q933_IE_VL_EXTENSION)
+                       goto l1_done;
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "%s duplex",
+                   (octet & 0x40) ? "Full" : "Half");
+               modem_type = octet & 0x3F;
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Modem type: Network-specific rules 0x%02X", modem_type);
+               offset += 1;
+               len -= 1;
+       }
+l1_done:
+       ;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       if ((octet & 0x60) == 0x40) {
+               /*
+                * Layer 2 information.
+                */
+               uil2_protocol = octet & 0x1F;
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "User information layer 2 protocol: %s",
+                   val_to_str(uil2_protocol, q933_uil2_vals,
+                     "Unknown (0x%02X)"));
+               offset += 1;
+               len -= 1;
+
+               /*
+                * XXX - only in Low-layer compatibility information element.
+                */
+               if (octet & Q933_IE_VL_EXTENSION)
+                       goto l2_done;
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               if (uil2_protocol == Q933_UIL2_USER_SPEC) {
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "User-specified layer 2 protocol information: 0x%02X",
+                           octet & 0x7F);
+               } else {
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Address inclusion: %s",
+                           val_to_str(octet & 0x03, q933_address_inclusion_vals,
+                             "Unknown (0x%02X)"));
+               }
+               offset += 1;
+               len -= 1;
+       }
+l2_done:
+       ;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       if ((octet & 0x60) == 0x60) {
+               /*
+                * Layer 3 information.
+                */
+               uil3_protocol = octet & 0x1F;
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "User information layer 3 protocol: %s",
+                   val_to_str(uil3_protocol, q933_uil3_vals,
+                     "Unknown (0x%02X)"));
+               offset += 1;
+               len -= 1;
+
+
+               /*
+                * XXX - only in Low-layer compatibility information element.
+                */
+               if (octet & Q933_IE_VL_EXTENSION)
+                       goto l3_done;
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               switch (uil3_protocol) {
+
+               case Q933_UIL3_X25_PL:
+               case Q933_UIL3_ISO_8208:
+               case Q933_UIL3_X223:
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Mode: %s",
+                           val_to_str(octet & 0x60, q933_mode_vals,
+                             "Unknown (0x%02X)"));
+                       offset += 1;
+                       len -= 1;
+
+                       if (octet & Q933_IE_VL_EXTENSION)
+                               goto l3_done;
+                       if (len == 0)
+                               return;
+                       octet = tvb_get_guint8(tvb, offset);
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Default packet size: %u", octet & 0x0F);
+                       offset += 1;
+                       len -= 1;
+
+                       if (octet & Q933_IE_VL_EXTENSION)
+                               goto l3_done;
+                       if (len == 0)
+                               return;
+                       octet = tvb_get_guint8(tvb, offset);
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Packet window size: %u", octet & 0x7F);
+                       offset += 1;
+                       len -= 1;
+                       break;
+
+               case Q933_UIL3_USER_SPEC:
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Default packet size: %u octets",
+                           1 << (octet & 0x0F));
+                       offset += 1;
+                       len -= 1;
+                       break;
+
+               case Q933_UIL3_TR_9577:
+                       add_l3_info = (octet & 0x0F) << 4;
+                       if (octet & Q933_IE_VL_EXTENSION)
+                               goto l3_done;
+                       if (len == 0)
+                               return;
+                       octet = tvb_get_guint8(tvb, offset + 1);
+                       add_l3_info |= (octet & 0x0F);
+                       proto_tree_add_text(tree, tvb, offset, 2,
+                           "Additional layer 3 protocol information: %s",
+                           val_to_str(add_l3_info, nlpid_vals,
+                             "Unknown (0x%02X)"));
+                       offset += 2;
+                       len -= 2;
+                       break;
+               }
+       }
+l3_done:
+       ;
+}
+
+/*
+ * Dissect a Cause information element.
+ */
+static const value_string q933_cause_coding_standard_vals[] = {
+       { 0x00, "ITU-T standardized coding" },
+       { 0x20, "ISO/IEC standard" },
+       { 0x40, "National standard" },
+       { 0x60, "Standard specific to identified location" },
+       { 0,    NULL }
+};
+
+const value_string q933_cause_location_vals[] = {
+       { 0x00, "User (U)" },
+       { 0x01, "Private network serving the local user (LPN)" },
+       { 0x02, "Public network serving the local user (LN)" },
+       { 0x03, "Transit network (TN)" },
+       { 0x04, "Public network serving the remote user (RLN)" },
+       { 0x05, "Private network serving the remote user (RPN)" },
+       { 0x07, "International network (INTL)" },
+       { 0x0A, "Network beyond interworking point (BI)" },
+       { 0,    NULL }
+};
+
+static const value_string q933_cause_recommendation_vals[] = {
+       { 0x00, "Q.933" },
+       { 0x03, "X.21" },
+       { 0x04, "X.25" },
+       { 0x05, "Q.1031/Q.1051" },
+       { 0,    NULL }
+};
+
+/*
+ * Cause codes for Cause.
+ */
+#define        Q933_CAUSE_UNALLOC_NUMBER       0x01
+#define        Q933_CAUSE_NO_ROUTE_TO_DEST     0x03
+#define        Q933_CAUSE_CALL_REJECTED        0x15
+#define        Q933_CAUSE_NUMBER_CHANGED       0x16
+#define        Q933_CAUSE_ACCESS_INFO_DISC     0x2B
+#define        Q933_CAUSE_QOS_UNAVAILABLE      0x31
+#define        Q933_CAUSE_CHAN_NONEXISTENT     0x52
+#define        Q933_CAUSE_INCOMPATIBLE_DEST    0x58
+#define        Q933_CAUSE_MAND_IE_MISSING      0x60
+#define        Q933_CAUSE_MT_NONEX_OR_UNIMPL   0x61
+#define        Q933_CAUSE_IE_NONEX_OR_UNIMPL   0x63
+#define        Q933_CAUSE_INVALID_IE_CONTENTS  0x64
+#define        Q933_CAUSE_MSG_INCOMPAT_W_CS    0x65
+#define        Q933_CAUSE_REC_TIMER_EXP        0x66
+
+const value_string q933_cause_code_vals[] = {
+       { 0x00,                         "Valid cause code not yet received" },
+       { Q933_CAUSE_UNALLOC_NUMBER,    "Unallocated (unassigned) number" },
+       { 0x02,                         "No route to specified transit network" },
+       { Q933_CAUSE_NO_ROUTE_TO_DEST,  "No route to destination" },
+       { 0x04,                         "Send special information tone" },
+       { 0x05,                         "Misdialled trunk prefix" },
+       { 0x06,                         "Channel unacceptable" },
+       { 0x07,                         "Call awarded and being delivered in an established channel" },
+       { 0x08,                         "Prefix 0 dialed but not allowed" },
+                                       /* Q.850 - "Preemption" */
+       { 0x09,                         "Prefix 1 dialed but not allowed" },
+                                       /* Q.850 - "Preemption - circuit reserved for reuse" */
+       { 0x0A,                         "Prefix 1 dialed but not required" },
+       { 0x0B,                         "More digits received than allowed, call is proceeding" },
+       { 0x0E,                         "QoR: ported number" },
+       { 0x10,                         "Normal call clearing" },
+       { 0x11,                         "User busy" },
+       { 0x12,                         "No user responding" },
+       { 0x13,                         "No answer from user (user alerted)" },
+       { 0x14,                         "Subscriber absent" },
+       { Q933_CAUSE_CALL_REJECTED,     "Call rejected" },
+       { Q933_CAUSE_NUMBER_CHANGED,    "Number changed" },
+       { 0x17,                         "Reverse charging rejected" },
+                                       /* Q.850 - "Redirection to new destination" */
+       { 0x18,                         "Call suspended" },
+                                       /* Q.850 Amendment 1 - "Call rejected due to feature at the destination" */
+       { 0x19,                         "Call resumed" },
+                                       /* Q.850 - "Exchange routing error */
+       { 0x1A,                         "Non-selected user clearing" },
+       { 0x1B,                         "Destination out of order" },
+       { 0x1C,                         "Invalid number format (incomplete number)" },
+       { 0x1D,                         "Facility rejected" },
+       { 0x1E,                         "Response to STATUS ENQUIRY" },
+       { 0x1F,                         "Normal unspecified" },
+       { 0x21,                         "Circuit out of order" },
+       { 0x22,                         "No circuit/channel available" },
+       { 0x23,                         "Destination unattainable" },
+       { 0x25,                         "Degraded service" },
+       { 0x26,                         "Network out of order" },
+       { 0x27,                         "Transit delay range cannot be achieved" },
+                                       /* Q.850 - "Permanent frame mode connection out of service" */
+       { 0x28,                         "Throughput range cannot be achieved" },
+                                       /* Q.850 - "Permanent frame mode connection operational" */
+       { 0x29,                         "Temporary failure" },
+       { 0x2A,                         "Switching equipment congestion" },
+       { Q933_CAUSE_ACCESS_INFO_DISC,  "Access information discarded" },
+       { 0x2C,                         "Requested circuit/channel not available" },
+       { 0x2D,                         "Pre-empted" },
+       { 0x2E,                         "Precedence call blocked" },
+       { 0x2F,                         "Resources unavailable, unspecified" },
+       { Q933_CAUSE_QOS_UNAVAILABLE,   "Quality of service unavailable" },
+       { 0x32,                         "Requested facility not subscribed" },
+       { 0x33,                         "Reverse charging not allowed" },
+       { 0x34,                         "Outgoing calls barred" },
+       { 0x35,                         "Outgoing calls barred within CUG" },
+       { 0x36,                         "Incoming calls barred" },
+       { 0x37,                         "Incoming calls barred within CUG" },
+       { 0x38,                         "Call waiting not subscribed" },
+       { 0x39,                         "Bearer capability not authorized" },
+       { 0x3A,                         "Bearer capability not presently available" },
+       { 0x3E,                         "Inconsistency in designated outgoing access information and subscriber class" },
+       { 0x3F,                         "Service or option not available, unspecified" },
+       { 0x41,                         "Bearer capability not implemented" },
+       { 0x42,                         "Channel type not implemented" },
+       { 0x43,                         "Transit network selection not implemented" },
+       { 0x44,                         "Message not implemented" },
+       { 0x45,                         "Requested facility not implemented" },
+       { 0x46,                         "Only restricted digital information bearer capability is available" },
+       { 0x4F,                         "Service or option not implemented, unspecified" },
+       { 0x51,                         "Invalid call reference value" },
+       { Q933_CAUSE_CHAN_NONEXISTENT,  "Identified channel does not exist" },
+       { 0x53,                         "Call identity does not exist for suspended call" },
+       { 0x54,                         "Call identity in use" },
+       { 0x55,                         "No call suspended" },
+       { 0x56,                         "Call having the requested call identity has been cleared" },
+       { 0x57,                         "Called user not member of CUG" },
+       { Q933_CAUSE_INCOMPATIBLE_DEST, "Incompatible destination" },
+       { 0x59,                         "Non-existent abbreviated address entry" },
+       { 0x5A,                         "Destination address missing, and direct call not subscribed" },
+                                       /* Q.850 - "Non-existent CUG" */
+       { 0x5B,                         "Invalid transit network selection (national use)" },
+       { 0x5C,                         "Invalid facility parameter" },
+       { 0x5D,                         "Mandatory information element is missing" },
+       { 0x5F,                         "Invalid message, unspecified" },
+       { Q933_CAUSE_MAND_IE_MISSING,   "Mandatory information element is missing" },
+       { Q933_CAUSE_MT_NONEX_OR_UNIMPL,"Message type non-existent or not implemented" },
+       { 0x62,                         "Message not compatible with call state or message type non-existent or not implemented" },
+       { Q933_CAUSE_IE_NONEX_OR_UNIMPL,"Information element nonexistant or not implemented" },
+       { Q933_CAUSE_INVALID_IE_CONTENTS,"Invalid information element contents" },
+       { Q933_CAUSE_MSG_INCOMPAT_W_CS, "Message not compatible with call state" },
+       { Q933_CAUSE_REC_TIMER_EXP,     "Recovery on timer expiry" },
+       { 0x67,                         "Parameter non-existent or not implemented - passed on" },
+       { 0x6E,                         "Message with unrecognized parameter discarded" },
+       { 0x6F,                         "Protocol error, unspecified" },
+       { 0x7F,                         "Internetworking, unspecified" },
+       { 0,                            NULL }
+};
+
+static const value_string q933_cause_condition_vals[] = {
+       { 0x00, "Unknown" },
+       { 0x01, "Permanent" },
+       { 0x02, "Transient" },
+       { 0x00, NULL }
+};
+
+#define        Q933_REJ_USER_SPECIFIC          0x00
+#define        Q933_REJ_IE_MISSING             0x04
+#define        Q933_REJ_IE_INSUFFICIENT        0x08
+
+static const value_string q933_rejection_reason_vals[] = {
+       { 0x00, "User specific" },
+       { 0x04, "Information element missing" },
+       { 0x08, "Information element contents are not sufficient" },
+       { 0x00, NULL }
+};
+
+void
+dissect_q933_cause_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree, int hf_cause_value)
+{
+       guint8 octet;
+       guint8 cause_value;
+       guint8 coding_standard;
+       guint8 rejection_reason;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       coding_standard = octet & 0x60;
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Coding standard: %s",
+           val_to_str(coding_standard, q933_cause_coding_standard_vals, NULL));
+       if (coding_standard != Q933_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_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, q933_cause_location_vals,
+             "Unknown (0x%X)"));
+       offset += 1;
+       len -= 1;
+
+       if (!(octet & Q933_IE_VL_EXTENSION)) {
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Recommendation: %s",
+                   val_to_str(octet & 0x7F, q933_cause_recommendation_vals,
+                     "Unknown (0x%02X)"));
+               offset += 1;
+               len -= 1;
+       }
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       cause_value = octet & 0x7F;
+       proto_tree_add_uint(tree, hf_cause_value, tvb, 0, 1, cause_value);
+       offset += 1;
+       len -= 1;
+
+       if (len == 0)
+               return;
+       switch (cause_value) {
+
+       case Q933_CAUSE_UNALLOC_NUMBER:
+       case Q933_CAUSE_NO_ROUTE_TO_DEST:
+       case Q933_CAUSE_QOS_UNAVAILABLE:
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Network service: %s",
+                   (octet & 0x80) ? "User" : "Provider");
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "%s",
+                   (octet & 0x40) ? "Abnormal" : "Normal");
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Condition: %s",
+                   val_to_str(octet & 0x03, q933_cause_condition_vals,
+                     "Unknown (0x%X)"));
+               break;
+
+       case Q933_CAUSE_CALL_REJECTED:
+               rejection_reason = octet & 0x7C;
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Rejection reason: %s",
+                   val_to_str(octet & 0x7C, q933_rejection_reason_vals,
+                     "Unknown (0x%X)"));
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Condition: %s",
+                   val_to_str(octet & 0x03, q933_cause_condition_vals,
+                     "Unknown (0x%X)"));
+               offset += 1;
+               len -= 1;
+
+               if (len == 0)
+                       return;
+               switch (rejection_reason) {
+
+               case Q933_REJ_USER_SPECIFIC:
+                       proto_tree_add_text(tree, tvb, offset, len,
+                           "User specific diagnostic: %s",
+                           tvb_bytes_to_str(tvb, offset, len));
+                       break;
+
+               case Q933_REJ_IE_MISSING:
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Missing information element: %s",
+                           val_to_str(tvb_get_guint8(tvb, offset), q933_info_element_vals0,
+                             "Unknown (0x%02X)"));
+                       break;
+
+               case Q933_REJ_IE_INSUFFICIENT:
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Insufficient information element: %s",
+                           val_to_str(tvb_get_guint8(tvb, offset), q933_info_element_vals0,
+                             "Unknown (0x%02X)"));
+                       break;
+
+               default:
+                       proto_tree_add_text(tree, tvb, offset, len,
+                           "Diagnostic: %s",
+                           tvb_bytes_to_str(tvb, offset, len));
+                       break;
+               }
+               break;
+
+       case Q933_CAUSE_ACCESS_INFO_DISC:
+       case Q933_CAUSE_INCOMPATIBLE_DEST:
+       case Q933_CAUSE_MAND_IE_MISSING:
+       case Q933_CAUSE_IE_NONEX_OR_UNIMPL:
+       case Q933_CAUSE_INVALID_IE_CONTENTS:
+               do {
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Information element: %s",
+                           val_to_str(tvb_get_guint8(tvb, offset), q933_info_element_vals0,
+                             "Unknown (0x%02X)"));
+                       offset += 1;
+                       len -= 1;
+               } while (len != 0);
+               break;
+
+       case Q933_CAUSE_MT_NONEX_OR_UNIMPL:
+       case Q933_CAUSE_MSG_INCOMPAT_W_CS:
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Message type: %s",
+                   val_to_str(tvb_get_guint8(tvb, offset), q933_message_type_vals,
+                     "Unknown (0x%02X)"));
+               break;
+
+       case Q933_CAUSE_REC_TIMER_EXP:
+               if (len < 3)
+                       return;
+               proto_tree_add_text(tree, tvb, offset, 3,
+                   "Timer: %.3s", tvb_get_ptr(tvb, offset, 3));
+               break;
+
+       default:
+               proto_tree_add_text(tree, tvb, offset, len,
+                   "Diagnostics: %s",
+                   tvb_bytes_to_str(tvb, offset, len));
+       }
+}
+
+/*
+ * Dissect a Call state information element.
+ */
+static const value_string q933_coding_standard_vals[] = {
+       { 0x00, "ITU-T standardized coding" },
+       { 0x20, "ISO/IEC standard" },
+       { 0x40, "National standard" },
+       { 0x60, "Standard defined for the network" },
+       { 0,    NULL }
+};
+
+static const value_string q933_call_state_vals[] = {
+       { 0x00, "Null" },
+       { 0x01, "Call initiated" },
+       { 0x02, "Overlap sending" },
+       { 0x03, "Outgoing call proceeding" },
+       { 0x04, "Call delivered" },
+       { 0x06, "Call present" },
+       { 0x07, "Call received" },
+       { 0x08, "Connect request" },
+       { 0x09, "Incoming call proceeding" },
+       { 0x0A, "Active" },
+       { 0x0B, "Disconnect request" },
+       { 0x0C, "Disconnect indication" },
+       { 0x0F, "Suspend request" },
+       { 0x12, "Resume request" },
+       { 0x13, "Release request" },
+       { 0x16, "Call abort"},
+       { 0x19, "Overlap receiving" },
+       { 0x3D, "Restart request" },
+       { 0x3E, "Restart" },
+       { 0,    NULL }
+};
+
+static void
+dissect_q933_call_state_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+       guint8 coding_standard;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       coding_standard = octet & 0x60;
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Coding standard: %s",
+           val_to_str(coding_standard, q933_coding_standard_vals, NULL));
+       if (coding_standard != Q933_ITU_STANDARDIZED_CODING) {
+               /*
+                * We don't know how the call state is encoded,
+                * so just dump it as data and be done with it.
+                */
+               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,
+           "Call state: %s",
+           val_to_str(octet & 0x3F, q933_call_state_vals,
+             "Unknown (0x%02X)"));
+}
+
+/*
+ * Dissect a Channel identification information element.
+ */
+#define        Q933_INTERFACE_IDENTIFIED       0x40
+#define        Q933_NOT_BASIC_CHANNEL          0x20
+
+static const value_string q933_basic_channel_selection_vals[] = {
+       { 0x00, "No channel" },
+       { 0x01, "B1 channel" },
+       { 0x02, "B2 channel" },
+       { 0x03, "Any channel" },
+       { 0,    NULL }
+};
+
+static const value_string q933_not_basic_channel_selection_vals[] = {
+       { 0x00, "No channel" },
+       { 0x01, "Channel indicated in following octets" },
+       { 0x03, "Any channel" },
+       { 0,    NULL }
+};
+
+#define        Q933_IS_SLOT_MAP                0x10
+
+static const value_string q933_element_type_vals[] = {
+       { 0x03, "B-channel units" },
+       { 0x06, "H0-channel units" },
+       { 0x08, "H11-channel units" },
+       { 0x09, "H12-channel units" },
+       { 0,    NULL }
+};
+
+static void
+dissect_q933_channel_identification_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+       int identifier_offset;
+       int identifier_len;
+       guint8 coding_standard;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Interface %s identified",
+           (octet & Q933_INTERFACE_IDENTIFIED) ? "explicitly" : "implicitly");
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "%s interface",
+           (octet & Q933_NOT_BASIC_CHANNEL) ? "Not basic" : "Basic");
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Indicated channel is %s",
+           (octet & 0x08) ? "required" : "preferred");
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Indicated channel is %sthe D-channel",
+           (octet & 0x04) ? "" : "not ");
+       if (octet & Q933_NOT_BASIC_CHANNEL) {
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Channel selection: %s",
+                   val_to_str(octet & 0x03, q933_not_basic_channel_selection_vals,
+                     "Unknown (0x%X)"));
+       } else {
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Channel selection: %s",
+                   val_to_str(octet & 0x03, q933_basic_channel_selection_vals,
+                     NULL));
+       }
+       offset += 1;
+       len -= 1;
+
+       if (octet & Q933_INTERFACE_IDENTIFIED) {
+               identifier_offset = offset;
+               identifier_len = 0;
+               do {
+                       if (len == 0)
+                               break;
+                       octet = tvb_get_guint8(tvb, offset);
+                       offset += 1;
+                       len -= 1;
+                       identifier_len++;
+               } while (!(octet & Q933_IE_VL_EXTENSION));
+
+               /*
+                * XXX - do we want to strip off the 8th bit on the
+                * last octet of the interface identifier?
+                */
+               if (identifier_len != 0) {
+                       proto_tree_add_text(tree, tvb, identifier_offset,
+                           identifier_len, "Interface identifier: %s",
+                           bytes_to_str(
+                             tvb_get_ptr(tvb, identifier_offset, identifier_len),
+                             identifier_len));
+               }
+       }
+
+       if (octet & Q933_NOT_BASIC_CHANNEL) {
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               coding_standard = octet & 0x60;
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Coding standard: %s",
+                   val_to_str(coding_standard, q933_coding_standard_vals,
+                     NULL));
+               if (coding_standard != Q933_ITU_STANDARDIZED_CODING) {
+                       /*
+                        * We don't know how the channel identifier is
+                        * encoded, so just dump it as data and be done
+                        * with it.
+                        */
+                       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,
+                   "Channel is indicated by %s",
+                   (octet & Q933_IS_SLOT_MAP) ? "slot map" : "number");
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "%s type: %s",
+                   (octet & Q933_IS_SLOT_MAP) ? "Map element" : "Channel",
+                   val_to_str(octet & 0x0F, q933_element_type_vals,
+                       "Unknown (0x%02X)"));
+
+               /*
+                * XXX - dump the channel number or slot map.
+                */
+       }
+}
+
+/*
+ * Dissect a Progress indicator information element.
+ */
+static const value_string q933_progress_description_vals[] = {
+       { 0x01, "Call is not end-to-end ISDN - progress information available in-band" },
+       { 0x02, "Destination address is non-ISDN" },
+       { 0x03, "Origination address is non-ISDN" },
+       { 0x04, "Call has returned to the ISDN" },
+       { 0x05, "Interworking has occurred and has resulted in a telecommunications service change" },
+       { 0x08, "In-band information or an appropriate pattern is now available" },
+       { 0,    NULL }
+};
+
+void
+dissect_q933_progress_indicator_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+       guint8 coding_standard;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       coding_standard = octet & 0x60;
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Coding standard: %s",
+           val_to_str(coding_standard, q933_cause_coding_standard_vals, NULL));
+       if (coding_standard != Q933_ITU_STANDARDIZED_CODING) {
+               /*
+                * We don't know how the progress indicator is encoded,
+                * so just dump it as data and be done with it.
+                */
+               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, q933_cause_location_vals,
+             "Unknown (0x%X)"));
+       offset += 1;
+       len -= 1;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Progress description: %s",
+           val_to_str(octet & 0x7F, q933_progress_description_vals,
+             "Unknown (0x%02X)"));
+}
+
+/*
+ * Dissect a Network-specific facilities or Transit network selection
+ * information element.
+ */
+static const value_string q933_netid_type_vals[] = {
+       { 0x00, "User specified" },
+       { 0x20, "National network identification" },
+       { 0x30, "International network identification" },
+       { 0,    NULL }
+};
+
+static const value_string q933_netid_plan_vals[] = {
+       { 0x00, "Unknown" },
+       { 0x01, "Carrier Identification Code" },
+       { 0x03, "X.121 data network identification code" },
+       { 0,    NULL }
+};
+
+static void
+dissect_q933_ns_facilities_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+       int netid_len;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       netid_len = octet & 0x7F;
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Network identification length: %u",
+           netid_len);
+       offset += 1;
+       len -= 1;
+       if (netid_len != 0) {
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Type of network identification: %s",
+                   val_to_str(octet & 0x70, q933_netid_type_vals,
+                     "Unknown (0x%02X)"));
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Network identification plan: %s",
+                   val_to_str(octet & 0x0F, q933_netid_plan_vals,
+                     "Unknown (0x%02X)"));
+               offset += 1;
+               len -= 1;
+               netid_len--;
+
+               if (len == 0)
+                       return;
+               if (netid_len > len)
+                       netid_len = len;
+               if (netid_len != 0) {
+                       proto_tree_add_text(tree, tvb, offset, netid_len,
+                           "Network identification: %s",
+                           tvb_format_text(tvb, offset, netid_len));
+                       offset += netid_len;
+                       len -= netid_len;
+               }
+       }
+
+       /*
+        * Whatever is left is the network-specific facility
+        * specification.
+        */
+        if (len == 0)
+               return;
+       proto_tree_add_text(tree, tvb, offset,
+           len, "Network-specific facility specification: %s",
+           tvb_bytes_to_str(tvb, offset, len));
+}
+
+static int
+dissect_q933_guint16_value(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree, char *label)
+{
+       guint8 octet;
+       guint16 value;
+       int value_len;
+
+       value_len = 0;
+
+       octet = tvb_get_guint8(tvb, offset);
+       if (octet & Q933_IE_VL_EXTENSION) {
+               /*
+                * Only one octet long - error.
+                */
+               goto bad_length;
+       }
+       value = (octet & 0x3) << 14;
+       offset += 1;
+       len -= 1;
+       value_len++;
+
+       if (len == 0) {
+               /*
+                * We've reached the end of the information element - error.
+                */
+               goto past_end;
+       }
+       octet = tvb_get_guint8(tvb, offset);
+       if (octet & Q933_IE_VL_EXTENSION) {
+               /*
+                * Only two octets long - error.
+                */
+               goto bad_length;
+       }
+       value |= (octet & 0x7F) << 7;
+       offset += 1;
+       len -= 1;
+       value_len++;
+
+       if (len == 0) {
+               /*
+                * We've reached the end of the information element - error.
+                */
+               goto past_end;
+       }
+       octet = tvb_get_guint8(tvb, offset);
+       if (!(octet & Q933_IE_VL_EXTENSION)) {
+               /*
+                * More than three octets long - error.
+                */
+               goto bad_length;
+       }
+       value |= (octet & 0x7F);
+       offset += 1;
+       len -= 1;
+       value_len++;
+
+       proto_tree_add_text(tree, tvb, offset, value_len, "%s: %u ms", label,
+           value);
+       return value_len;
+
+past_end:
+       proto_tree_add_text(tree, tvb, offset, len,
+           "%s goes past end of information element", label);
+       return -1;
+
+bad_length:
+       proto_tree_add_text(tree, tvb, offset, len, "%s isn't 3 octets long",
+           label);
+       return -1;
+}
+
+/*
+ * Dissect an End-to-end transit delay information element.
+ */
+static void
+dissect_q933_e2e_transit_delay_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       int value_len;
+
+       if (len == 0)
+               return;
+       value_len = dissect_q933_guint16_value(tvb, offset, len, tree,
+           "Cumulative transit delay");
+       if (value_len < 0)
+               return; /* error */
+       offset += value_len;
+       len -= value_len;
+
+       if (len == 0)
+               return;
+       value_len = dissect_q933_guint16_value(tvb, offset, len, tree,
+           "Requested end-to-end transit delay");
+       if (value_len < 0)
+               return; /* error */
+       offset += value_len;
+       len -= value_len;
+
+       if (len == 0)
+               return;
+       value_len = dissect_q933_guint16_value(tvb, offset, len, tree,
+           "Maximum end-to-end transit delay");
+}
+
+/*
+ * Dissect a Transit delay selection and indication information element.
+ */
+static void
+dissect_q933_td_selection_and_int_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       if (len == 0)
+               return;
+       dissect_q933_guint16_value(tvb, offset, len, tree,
+           "Transit delay");
+}
+
+static void
+dissect_q933_pl_binary_parameters_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "%s",
+           (octet & 0x04) ? "No request/request denied" :
+                            "Request indicated/request accepted");
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "%s confirmation",
+           (octet & 0x02) ? "Link-by-link" : "End-to-end");
+}
+
+/*
+ * Dissect a Reverse charging indication information element.
+ */
+static const value_string q933_reverse_charging_indication_vals[] = {
+       { 0x01, "Reverse charging requested" },
+       { 0,    NULL }
+};
+
+static void
+dissect_q933_reverse_charge_ind_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       if (len == 0)
+               return;
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Reverse charging indication: %s",
+           val_to_str(tvb_get_guint8(tvb, offset) & 0x07,
+             q933_reverse_charging_indication_vals, "Unknown (0x%02X)"));
+}
+
+/*
+ * Dissect a (phone) number information element.
+ */
+static const value_string q933_number_type_vals[] = {
+       { 0x00, "Unknown" },
+       { 0x10, "International number" },
+       { 0x20, "National number" },
+       { 0x30, "Network specific number" },
+       { 0x40, "Subscriber number" },
+       { 0x60, "Abbreviated number" },
+       { 0,    NULL }
+};
+
+static const value_string q933_numbering_plan_vals[] = {
+       { 0x00, "Unknown" },
+       { 0x01, "E.164 ISDN/telephony numbering" },
+       { 0x03, "X.121 data numbering" },
+       { 0x04, "F.69 Telex numbering" },
+       { 0x08, "National standard numbering" },
+       { 0x09, "Private numbering" },
+       { 0,    NULL }
+};
+
+static const value_string q933_presentation_indicator_vals[] = {
+       { 0x00, "Presentation allowed" },
+       { 0x20, "Presentation restricted" },
+       { 0x40, "Number not available due to interworking" },
+       { 0,    NULL }
+};
+
+static const value_string q933_screening_indicator_vals[] = {
+       { 0x00, "User-provided, not screened" },
+       { 0x01, "User-provided, verified and passed" },
+       { 0x02, "User-provided, verified and failed" },
+       { 0x03, "Network-provided" },
+       { 0,    NULL }
+};
+
+static const value_string q933_redirection_reason_vals[] = {
+       { 0x00, "Unknown" },
+       { 0x01, "Call forwarding busy or called DTE busy" },
+       { 0x02, "Call forwarding no reply" },
+       { 0x04, "Call deflection" },
+       { 0x09, "Called DTE out of order" },
+       { 0x0A, "Call forwarding by the called DTE" },
+       { 0x0F, "Call forwarding unconditional or systematic call redirection" },
+       { 0,    NULL }
+};
+
+static void
+dissect_q933_number_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree, int hfindex)
+{
+       guint8 octet;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Type of number: %s",
+           val_to_str(octet & 0x70, q933_number_type_vals,
+             "Unknown (0x%02X)"));
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Numbering plan: %s",
+           val_to_str(octet & 0x0F, q933_numbering_plan_vals,
+             "Unknown (0x%02X)"));
+       offset += 1;
+       len -= 1;
+
+       if (!(octet & Q933_IE_VL_EXTENSION)) {
+               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, q933_presentation_indicator_vals,
+                     "Unknown (0x%X)"));
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Screening indicator: %s",
+                   val_to_str(octet & 0x03, q933_screening_indicator_vals,
+                     "Unknown (0x%X)"));
+               offset += 1;
+               len -= 1;
+       }
+
+       /*
+        * XXX - only in a Redirecting number information element.
+        */
+       if (!(octet & Q933_IE_VL_EXTENSION)) {
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(tree, tvb, offset, 1,
+                   "Reason for redirection: %s",
+                   val_to_str(octet & 0x0F, q933_redirection_reason_vals,
+                     "Unknown (0x%X)"));
+               offset += 1;
+               len -= 1;
+       }
+
+       if (len == 0)
+               return;
+       proto_tree_add_item(tree, hfindex, tvb, offset, len, FALSE);
+}
+
+/*
+ * Dissect a party subaddress information element.
+ */
+static const value_string q933_subaddress_type_vals[] = {
+       { 0x00, "X.213/ISO 8348 Add.2 NSAP" },
+       { 0x20, "User-specified" },
+       { 0,    NULL }
+};
+
+static const value_string q933_odd_even_indicator_vals[] = {
+       { 0x00, "Even number of address signals" },
+       { 0x10, "Odd number of address signals" },
+       { 0,    NULL }
+};
+
+static void
+dissect_q933_party_subaddr_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Type of subaddress: %s",
+           val_to_str(octet & 0x70, q933_subaddress_type_vals,
+             "Unknown (0x%02X)"));
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Odd/even indicator: %s",
+           val_to_str(octet & 0x10, q933_odd_even_indicator_vals,
+             NULL));
+       offset += 1;
+       len -= 1;
+
+       if (len == 0)
+               return;
+       proto_tree_add_text(tree, tvb, offset, len, "Subaddress: %s",
+           tvb_bytes_to_str(tvb, offset, len));
+}
+
+/*
+ * Dissect a High-layer compatibility information element.
+ */
+#define        Q933_AUDIOVISUAL        0x60
+static const value_string q933_high_layer_characteristics_vals[] = {
+       { 0x01,             "Telephony" },
+       { 0x04,             "F.182 Facsimile Group 2/3" },
+       { 0x21,             "F.184 Facsimile Group 4 Class I" },
+       { 0x24,             "F.230 Teletex, basic and mixed mode, and F.184 Facsimile Group 4, Classes II and III" },
+       { 0x28,             "F.220 Teletex, basic and processable mode" },
+       { 0x31,             "F.200 Teletex, basic mode" },
+       { 0x32,             "F.300 and T.102 syntax-based Videotex" },
+       { 0x33,             "F.300 and T.101 international Videotex interworking" },
+       { 0x35,             "F.60 Telex" },
+       { 0x38,             "X.400 Message Handling Systems" },
+       { 0x41,             "X.200 OSI application" },
+       { 0x42,             "FTAM application" },
+       { 0x5E,             "Reserved for maintenance" },
+       { 0x5F,             "Reserved for management" },
+       { Q933_AUDIOVISUAL, "F.720/F.821 and F.731 Profile 1a videotelephony" },
+       { 0x61,             "F.702 and F.731 Profile 1b videoconferencing" },
+       { 0x62,             "F.702 and F.731 audiographic conferencing" },
+       { 0,                NULL }
+};
+
+static const value_string q933_audiovisual_characteristics_vals[] = {
+       { 0x01, "Capability set of initial channel of H.221" },
+       { 0x02, "Capability set of subsequent channel of H.221" },
+       { 0x21, "Capability set of initial channel of an active 3.1kHz audio or speech call" },
+       { 0x00, NULL }
+};
+
+void
+dissect_q933_high_layer_compat_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+       guint8 coding_standard;
+       guint8 characteristics;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       coding_standard = octet & 0x60;
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Coding standard: %s",
+           val_to_str(coding_standard, q933_coding_standard_vals, NULL));
+       offset += 1;
+       len -= 1;
+       if (coding_standard != Q933_ITU_STANDARDIZED_CODING) {
+               /*
+                * We don't know how the call state is encoded,
+                * so just dump it as data and be done with it.
+                */
+               proto_tree_add_text(tree, tvb, offset,
+                   len, "Data: %s",
+                   tvb_bytes_to_str(tvb, offset, len));
+               return;
+       }
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       characteristics = octet & 0x7F;
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "High layer characteristics identification: %s",
+           val_to_str(characteristics, q933_high_layer_characteristics_vals,
+            "Unknown (0x%02X)"));
+       offset += 1;
+       len -= 1;
+
+       if (!(octet & Q933_IE_VL_EXTENSION)) {
+               if (len == 0)
+                       return;
+               octet = tvb_get_guint8(tvb, offset);
+               if (characteristics == Q933_AUDIOVISUAL) {
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Extended audiovisual characteristics identification: %s",
+                           val_to_str(octet & 0x7F,
+                             q933_audiovisual_characteristics_vals,
+                             "Unknown (0x%02X)"));
+               } else {
+                       proto_tree_add_text(tree, tvb, offset, 1,
+                           "Extended high layer characteristics identification: %s",
+                           val_to_str(octet & 0x7F,
+                             q933_high_layer_characteristics_vals,
+                             "Unknown (0x%02X)"));
+               }
+       }
+}
+
+
+/*
+ * Dissect a User-user information element.
+ */
+#define        Q933_PROTOCOL_DISCRIMINATOR_IA5         0x04
+#define Q933_PROTOCOL_DISCRIMINATOR_ASN1       0x05
+
+static const value_string q933_protocol_discriminator_vals[] = {
+       { 0x00,                                 "User-specific protocol" },
+       { 0x01,                                 "OSI high layer protocols" },
+       { 0x02,                                 "X.244" },
+       { Q933_PROTOCOL_DISCRIMINATOR_IA5,      "IA5 characters" },
+       { Q933_PROTOCOL_DISCRIMINATOR_ASN1,     "X.208 and X.209 coded user information" },
+       { 0x07,                                 "V.120 rate adaption" },
+       { 0x08,                                 "Q.933/I.451 user-network call control messages" },
+       { 0,                                    NULL }
+};
+
+void
+dissect_q933_user_user_ie(tvbuff_t *tvb, int offset, int len,
+    proto_tree *tree)
+{
+       guint8 octet;
+
+       if (len == 0)
+               return;
+       octet = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree, tvb, offset, 1,
+           "Protocol discriminator: %s",
+           val_to_str(octet, q933_protocol_discriminator_vals,
+           "Unknown (0x%02x)"));
+       offset += 1;
+       len -= 1;
+
+       if (len == 0)
+               return;
+       switch (octet) {
+
+       case Q933_PROTOCOL_DISCRIMINATOR_IA5:
+               proto_tree_add_text(tree, tvb, offset, len, "User information: %s",
+                   tvb_format_text(tvb, offset, len));
+               break;
+
+       default:
+               proto_tree_add_text(tree, tvb, offset, len, "User information: %s",
+                   tvb_bytes_to_str(tvb, offset, len));
+               break;
+       }
+}
+
+/*
+ * Dissect information elements consisting of ASCII^H^H^H^H^HIA5 text.
+ */
+static void
+dissect_q933_ia5_ie(tvbuff_t *tvb, int offset, int len, proto_tree *tree,
+    char *label)
+{
+       if (len != 0) {
+               proto_tree_add_text(tree, tvb, offset, len, "%s: %s", label,
+                   tvb_format_text(tvb, offset, len));
+       }
+}
+
+static const value_string q933_codeset_vals[] = {
+       { 0x00, "Q.933 information elements" },
+       { 0x04, "Information elements for ISO/IEC use" },
+       { 0x05, "Information elements for national use" },
+       { 0x06, "Information elements specific to the local network" },
+       { 0x07, "User-specific information elements" },
+       { 0x00, NULL },
+};
+
+static void
+dissect_q933(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       int             offset = 0;
+       proto_tree      *q933_tree = NULL;
+       proto_item      *ti;
+       proto_tree      *ie_tree = NULL;
+       guint8          call_ref_len;
+       guint8          call_ref[15];
+       guint8          message_type;
+       guint8          info_element;
+       guint16         info_element_len;
+       int             codeset, locked_codeset;
+       gboolean        non_locking_shift;
+
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "Q.933");
+
+       if (tree) {
+               ti = proto_tree_add_item(tree, proto_q933, tvb, offset, -1,
+                   FALSE);
+               q933_tree = proto_item_add_subtree(ti, ett_q933);
+
+               dissect_q933_protocol_discriminator(tvb, offset, q933_tree);
+       }
+       offset += 1;
+       call_ref_len = tvb_get_guint8(tvb, offset) & 0xF;       /* XXX - do as a bit field? */
+       if (q933_tree != NULL)
+               proto_tree_add_uint(q933_tree, hf_q933_call_ref_len, tvb, offset, 1, call_ref_len);
+       offset += 1;
+       if (call_ref_len != 0) {
+               tvb_memcpy(tvb, call_ref, offset, call_ref_len);
+               if (q933_tree != NULL) {
+                       proto_tree_add_boolean(q933_tree, hf_q933_call_ref_flag,
+                           tvb, offset, 1, (call_ref[0] & 0x80) != 0);
+                       call_ref[0] &= 0x7F;
+                       proto_tree_add_bytes(q933_tree, hf_q933_call_ref,
+                           tvb, offset, call_ref_len, call_ref);
+               }
+               offset += call_ref_len;
+       }
+       message_type = tvb_get_guint8(tvb, offset);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_add_str(pinfo->cinfo, COL_INFO,
+                   val_to_str(message_type, q933_message_type_vals,
+                     "Unknown message type (0x%02X)"));
+       }
+       if (q933_tree != NULL)
+               proto_tree_add_uint(q933_tree, hf_q933_message_type, tvb, offset, 1, message_type);
+       offset += 1;
+
+       /*
+        * And now for the information elements....
+        */
+       codeset = locked_codeset = 0;   /* start out in codeset 0 */
+       non_locking_shift = TRUE;
+       while (tvb_reported_length_remaining(tvb, offset) > 0) {
+               info_element = tvb_get_guint8(tvb, offset);
+
+                /* Check for the codeset shift */
+               if ((info_element & Q933_IE_SO_MASK) &&
+                   ((info_element & Q933_IE_SO_IDENTIFIER_MASK) == Q933_IE_SHIFT)) {
+                       non_locking_shift = info_element & Q933_IE_SHIFT_NON_LOCKING;
+                       codeset = info_element & Q933_IE_SHIFT_CODESET;
+                       if (!non_locking_shift)
+                               locked_codeset = codeset;
+                       if (q933_tree != NULL) {
+                               proto_tree_add_text(q933_tree, tvb, offset, 1,
+                                   "%s shift to codeset %u: %s",
+                                   (non_locking_shift ? "Non-locking" : "Locking"),
+                                   codeset,
+                                   val_to_str(codeset, q933_codeset_vals,
+                                     "Unknown (0x%02X)"));
+                       }
+                       offset += 1;
+                       continue;
+               }
+
+               /*
+                * Check for the single-octet IEs.
+                */
+               if (info_element & Q933_IE_SO_MASK) {
+                       switch ((codeset << 8) | (info_element & Q933_IE_SO_IDENTIFIER_MASK)) {
+
+                       case CS0 | Q933_IE_REPEAT_INDICATOR:
+                               if (q933_tree != NULL) {
+                                       proto_tree_add_text(q933_tree, tvb, offset, 1,
+                                           "Repeat indicator: %s",
+                                           val_to_str(info_element & Q933_IE_SO_IE_MASK,
+                                         q933_repeat_indication_vals,
+                                             "Unknown (0x%X)"));
+                               }
+                               break;
+
+                       default:
+                               if (q933_tree != NULL) {
+                                       proto_tree_add_text(q933_tree, tvb, offset, 1,
+                                           "Unknown information element (0x%02X)",
+                                           info_element);
+                               }
+                               break;
+                       }
+                       offset += 1;
+                       codeset = locked_codeset;
+                       continue;
+               }
+
+               /*
+                * Variable-length IE.
+                */
+               info_element_len = tvb_get_guint8(tvb, offset + 1);
+               if (q933_tree != NULL) {
+                       ti = proto_tree_add_text(q933_tree, tvb, offset,
+                           1+1+info_element_len, "%s",
+                           val_to_str(info_element, q933_info_element_vals[codeset],
+                             "Unknown information element (0x%02X)"));
+                               ie_tree = proto_item_add_subtree(ti, ett_q933_ie);
+                       proto_tree_add_text(ie_tree, tvb, offset, 1,
+                           "Information element: %s",
+                           val_to_str(info_element, q933_info_element_vals[codeset],
+                             "Unknown (0x%02X)"));
+                       proto_tree_add_text(ie_tree, tvb, offset + 1, 1,
+                           "Length: %u", info_element_len);
+
+                       switch ((codeset << 8) | info_element) {
+
+                       case CS0 | Q933_IE_SEGMENTED_MESSAGE:
+                               dissect_q933_segmented_message_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_BEARER_CAPABILITY:
+                       case CS0 | Q933_IE_LOW_LAYER_COMPAT:
+                               dissect_q933_bearer_capability_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_CAUSE:
+                               dissect_q933_cause_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree,
+                                   hf_q933_cause_value);
+                               break;
+
+                       case CS0 | Q933_IE_CALL_STATE:
+                               dissect_q933_call_state_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_CHANNEL_IDENTIFICATION:
+                               dissect_q933_channel_identification_ie(
+                                   tvb, offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_PROGRESS_INDICATOR:
+                               dissect_q933_progress_indicator_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_NETWORK_SPECIFIC_FACIL:
+                       case CS0 | Q933_IE_TRANSIT_NETWORK_SEL:
+                               dissect_q933_ns_facilities_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_DISPLAY:
+                               dissect_q933_ia5_ie(tvb, offset + 2,
+                                   info_element_len, ie_tree,
+                                   "Display information");
+                               break;
+
+                       case CS0 | Q933_IE_E2E_TRANSIT_DELAY:
+                               dissect_q933_e2e_transit_delay_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_TD_SELECTION_AND_INT:
+                               dissect_q933_td_selection_and_int_ie(
+                                   tvb, offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_PL_BINARY_PARAMETERS:
+                               dissect_q933_pl_binary_parameters_ie(
+                                   tvb, offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_REVERSE_CHARGE_IND:
+                               dissect_q933_reverse_charge_ind_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_CALLING_PARTY_NUMBER:
+                               dissect_q933_number_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree,
+                                   hf_q933_calling_party_number);
+                               break;
+
+                       case CS0 | Q933_IE_CONNECTED_NUMBER:
+                               dissect_q933_number_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree,
+                                   hf_q933_connected_number);
+                               break;
+
+                       case CS0 | Q933_IE_CALLED_PARTY_NUMBER:
+                               dissect_q933_number_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree,
+                                   hf_q933_called_party_number);
+                               break;
+
+                       case CS0 | Q933_IE_CALLING_PARTY_SUBADDR:
+                       case CS0 | Q933_IE_CALLED_PARTY_SUBADDR:
+                               dissect_q933_party_subaddr_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_HIGH_LAYER_COMPAT:
+                               dissect_q933_high_layer_compat_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       case CS0 | Q933_IE_USER_USER:
+                               dissect_q933_user_user_ie(tvb,
+                                   offset + 2, info_element_len,
+                                   ie_tree);
+                               break;
+
+                       default:
+                               proto_tree_add_text(ie_tree, tvb,
+                                   offset + 2, info_element_len,
+                                   "Data: %s",
+                                   bytes_to_str(
+                                     tvb_get_ptr(tvb, offset + 2,
+                                         info_element_len),
+                                         info_element_len));
+                               break;
+                       }
+               }
+               offset += 1 + 1 + info_element_len;
+               codeset = locked_codeset;
+       }
+}
+
+void
+proto_register_q933(void)
+{
+       static hf_register_info hf[] = {
+               { &hf_q933_discriminator,
+                 { "Protocol discriminator", "q933.disc", FT_UINT8, BASE_HEX, NULL, 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_call_ref_len,
+                 { "Call reference value length", "q933.call_ref_len", FT_UINT8, BASE_DEC, NULL, 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_call_ref_flag,
+                 { "Call reference flag", "q933.call_ref_flag", FT_BOOLEAN, BASE_NONE, TFS(&tfs_call_ref_flag), 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_call_ref,
+                 { "Call reference value", "q933.call_ref", FT_BYTES, BASE_HEX, NULL, 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_message_type,
+                 { "Message type", "q933.message_type", FT_UINT8, BASE_HEX, VALS(q933_message_type_vals), 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_cause_value,
+                 { "Cause value", "q933.cause_value", FT_UINT8, BASE_DEC, VALS(q933_cause_code_vals), 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_calling_party_number,
+                 { "Calling party number digits", "q933.calling_party_number.digits", FT_STRING, BASE_NONE, NULL, 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_called_party_number,
+                 { "Called party number digits", "q933.called_party_number.digits", FT_STRING, BASE_NONE, NULL, 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_connected_number,
+                 { "Connected party number digits", "q933.connected_number.digits", FT_STRING, BASE_NONE, NULL, 0x0,
+                       "", HFILL }},
+
+               { &hf_q933_redirecting_number,
+                 { "Redirecting party number digits", "q933.redirecting_number.digits", FT_STRING, BASE_NONE, NULL, 0x0,
+                       "", HFILL }},
+       };
+       static gint *ett[] = {
+               &ett_q933,
+               &ett_q933_ie,
+       };
+
+       proto_q933 = proto_register_protocol("Q.933", "Q.933", "q933");
+       proto_register_field_array (proto_q933, hf, array_length(hf));
+       proto_register_subtree_array(ett, array_length(ett));
+
+       register_dissector("q933", dissect_q933, proto_q933);
+}
+
+void
+proto_reg_handoff_q933(void)
+{
+       dissector_handle_t q933_handle;
+
+       q933_handle = create_dissector_handle(dissect_q933, proto_q933);
+       dissector_add("fr.osinl", NLPID_Q_933, q933_handle);
+}