A new type of DCERPC over SMB transport.
[obnox/wireshark/wip.git] / packet-wsp.c
index 21f728d71f390f97464fa4a24eb39a757dd7df22..a71ce47628a487a31203554627f096d8200fdb1c 100644 (file)
@@ -2,15 +2,16 @@
  *
  * Routines to dissect WSP component of WAP traffic.
  * 
- * $Id: packet-wsp.c,v 1.30 2001/07/20 09:22:05 guy Exp $
+ * $Id: packet-wsp.c,v 1.54 2002/02/22 07:23:24 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
- * Copyright 1998 Didier Jorand
+ * Copyright 1998 Gerald Combs
  *
  * WAP dissector based on original work by Ben Fowler
  * Updated by Neil Hunter <neil.hunter@energis-squared.com>
  * WTLS support by Alexandre P. Ferreira (Splice IP)
+ * Openwave header support by Dermot Bradley <dermot.bradley@openwave.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -53,9 +54,9 @@
 
 #include <string.h>
 #include <glib.h>
-#include "packet.h"
-#include "ipv6-utils.h"
-#include "conversation.h"
+#include <epan/packet.h>
+#include <epan/ipv6-utils.h>
+#include <epan/conversation.h>
 #include "packet-wap.h"
 #include "packet-wsp.h"
 
@@ -95,8 +96,13 @@ static int hf_wsp_parameter_start_info                       = HF_EMPTY;
 static int hf_wsp_parameter_comment                    = HF_EMPTY;
 static int hf_wsp_parameter_domain                     = HF_EMPTY;
 static int hf_wsp_parameter_path                       = HF_EMPTY;
+static int hf_wsp_parameter_upart_type                 = HF_EMPTY;
+static int hf_wsp_parameter_upart_type_value           = HF_EMPTY;
 static int hf_wsp_reply_data                           = HF_EMPTY;
 static int hf_wsp_post_data                            = HF_EMPTY;
+static int hf_wsp_push_data                            = HF_EMPTY;
+static int hf_wsp_multipart_data                       = HF_EMPTY;
+static int hf_wsp_mpart                                        = HF_EMPTY;
 
 static int hf_wsp_header_shift_code                    = HF_EMPTY;
 static int hf_wsp_header_accept                                = HF_EMPTY;
@@ -112,6 +118,8 @@ static int hf_wsp_header_accept_ranges_str          = HF_EMPTY;
 static int hf_wsp_header_cache_control                 = HF_EMPTY;
 static int hf_wsp_header_cache_control_str             = HF_EMPTY;
 static int hf_wsp_header_cache_control_field_name      = HF_EMPTY;
+static int hf_wsp_header_connection                    = HF_EMPTY;
+static int hf_wsp_header_connection_str                        = HF_EMPTY;
 static int hf_wsp_header_cache_control_field_name_str  = HF_EMPTY;
 static int hf_wsp_header_content_length                        = HF_EMPTY;
 static int hf_wsp_header_age                           = HF_EMPTY;
@@ -133,9 +141,47 @@ static int hf_wsp_header_warning_text                      = HF_EMPTY;
 static int hf_wsp_header_application_header            = HF_EMPTY;
 static int hf_wsp_header_application_value             = HF_EMPTY;
 static int hf_wsp_header_x_wap_tod                     = HF_EMPTY;
+static int hf_wsp_header_content_ID                    = HF_EMPTY;
 static int hf_wsp_header_transfer_encoding             = HF_EMPTY;
 static int hf_wsp_header_transfer_encoding_str         = HF_EMPTY;
 static int hf_wsp_header_via                           = HF_EMPTY;
+static int hf_wsp_header_wap_application_id            = HF_EMPTY;
+static int hf_wsp_header_wap_application_id_str                = HF_EMPTY;
+
+
+/* Openwave-specific WSP headers */
+static int hf_wsp_header_openwave_proxy_push_addr      = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_push_accept    = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_push_seq       = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_notify         = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_operator_domain        = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_home_page      = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_has_color     = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_num_softkeys  = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_softkey_size  = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_screen_chars  = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_screen_pixels = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_em_size       = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_screen_depth  = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_immed_alert   = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_net_ask                = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_uplink_version = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_tod            = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_ba_enable      = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_ba_realm       = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_redirect_enable        = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_request_uri    = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_redirect_status        = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_trans_charset  = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_trans_charset_str      = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_linger         = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_client_id      = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_enable_trust   = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_trust_old      = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_trust          = HF_EMPTY;
+static int hf_wsp_header_openwave_proxy_bookmark       = HF_EMPTY;
+static int hf_wsp_header_openwave_devcap_gui           = HF_EMPTY;
+
 
 static int hf_wsp_redirect_flags                       = HF_EMPTY;
 static int hf_wsp_redirect_permanent                   = HF_EMPTY;
@@ -162,6 +208,14 @@ static gint ett_capabilities                               = ETT_EMPTY;
 static gint ett_content_type                           = ETT_EMPTY;
 static gint ett_redirect_flags                         = ETT_EMPTY;
 static gint ett_redirect_afl                           = ETT_EMPTY;
+static gint ett_multiparts                             = ETT_EMPTY;
+static gint ett_mpartlist                              = ETT_EMPTY;
+
+/* Handle for WSP-over-UDP dissector */
+static dissector_handle_t wsp_fromudp_handle;
+
+/* Handle for WTP-over-UDP dissector */
+static dissector_handle_t wtp_fromudp_handle;
 
 /* Handle for WMLC dissector */
 static dissector_handle_t wmlc_handle;
@@ -220,6 +274,7 @@ static const value_string vals_status[] = {
        { 0x33, "See Other" },
        { 0x34, "Not Modified" },
        { 0x35, "Use Proxy" },
+       { 0x37, "Temporary Redirect" },
 
        { 0x40, "Bad Request" },
        { 0x41, "Unauthorised" },
@@ -237,6 +292,8 @@ static const value_string vals_status[] = {
        { 0x4D, "Request Entity Too Large" },
        { 0x4E, "Request-URI Too Large" },
        { 0x4F, "Unsupported Media Type" },
+       { 0x50, "Requested Range Not Satisfiable" },
+       { 0x51, "Expectation Failed" },
 
        { 0x60, "Internal Server Error" },
        { 0x61, "Not Implemented" },
@@ -318,6 +375,80 @@ static const value_string vals_status[] = {
 #define FN_SET_COOKIE          0x41
 #define FN_COOKIE              0x42
 #define FN_ENCODING_VERSION    0x43
+#define FN_PROFILE_WARNING14   0x44    /* encoding version 1.4 */
+#define FN_CONTENT_DISPOSITION14       0x45    /* encoding version 1.4 */
+#define FN_X_WAP_SECURITY      0x46
+#define FN_CACHE_CONTROL14     0x47    /* encoding version 1.4 */
+
+
+/*
+ * Openwave field names.
+ */
+#define FN_OPENWAVE_PROXY_PUSH_ADDR            0x00
+#define FN_OPENWAVE_PROXY_PUSH_ACCEPT          0x01
+#define FN_OPENWAVE_PROXY_PUSH_SEQ             0x02
+#define FN_OPENWAVE_PROXY_NOTIFY               0x03
+#define FN_OPENWAVE_PROXY_OPERATOR_DOMAIN      0x04
+#define FN_OPENWAVE_PROXY_HOME_PAGE            0x05
+#define FN_OPENWAVE_DEVCAP_HAS_COLOR           0x06
+#define FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS                0x07
+#define FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE                0x08
+#define FN_OPENWAVE_DEVCAP_SCREEN_CHARS                0x09
+#define FN_OPENWAVE_DEVCAP_SCREEN_PIXELS       0x0A
+#define FN_OPENWAVE_DEVCAP_EM_SIZE             0x0B
+#define FN_OPENWAVE_DEVCAP_SCREEN_DEPTH                0x0C
+#define FN_OPENWAVE_DEVCAP_IMMED_ALERT         0x0D
+#define FN_OPENWAVE_PROXY_NET_ASK              0x0E
+#define FN_OPENWAVE_PROXY_UPLINK_VERSION       0x0F
+#define FN_OPENWAVE_PROXY_TOD                  0x10
+#define FN_OPENWAVE_PROXY_BA_ENABLE            0x11
+#define FN_OPENWAVE_PROXY_BA_REALM             0x12
+#define FN_OPENWAVE_PROXY_REDIRECT_ENABLE      0x13
+#define FN_OPENWAVE_PROXY_REQUEST_URI          0x14
+#define FN_OPENWAVE_PROXY_REDIRECT_STATUS      0x15
+#define FN_OPENWAVE_PROXY_TRANS_CHARSET                0x16
+#define FN_OPENWAVE_PROXY_LINGER               0x17
+#define FN_OPENWAVE_PROXY_CLIENT_ID            0x18
+#define FN_OPENWAVE_PROXY_ENABLE_TRUST         0x19
+#define FN_OPENWAVE_PROXY_TRUST_OLD            0x1A
+#define FN_OPENWAVE_PROXY_TRUST                        0x20
+#define FN_OPENWAVE_PROXY_BOOKMARK             0x21
+#define FN_OPENWAVE_DEVCAP_GUI                 0x22
+
+static const value_string vals_openwave_field_names[] = {
+       { FN_OPENWAVE_PROXY_PUSH_ADDR,         "x-up-proxy-push-addr" },
+       { FN_OPENWAVE_PROXY_PUSH_ACCEPT,       "x-up-proxy-push-accept" },
+       { FN_OPENWAVE_PROXY_PUSH_SEQ,          "x-up-proxy-seq" },
+       { FN_OPENWAVE_PROXY_NOTIFY,            "x-up-proxy-notify" },
+       { FN_OPENWAVE_PROXY_OPERATOR_DOMAIN,   "x-up-proxy-operator-domain" },
+       { FN_OPENWAVE_PROXY_HOME_PAGE,         "x-up-proxy-home-page" },
+       { FN_OPENWAVE_DEVCAP_HAS_COLOR,        "x-up-devcap-has-color" },
+       { FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS,     "x-up-devcap-num-softkeys" },
+       { FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE,     "x-up-devcap-softkey-size" },
+       { FN_OPENWAVE_DEVCAP_SCREEN_CHARS,     "x-up-devcap-screen-chars" },
+       { FN_OPENWAVE_DEVCAP_SCREEN_PIXELS,    "x-up-devcap-screen-pixels" },
+       { FN_OPENWAVE_DEVCAP_EM_SIZE,          "x-up-devcap-em-size" },
+       { FN_OPENWAVE_DEVCAP_SCREEN_DEPTH,     "x-up-devcap-screen-depth" },
+       { FN_OPENWAVE_DEVCAP_IMMED_ALERT,      "x-up-devcap-immed-alert" },
+       { FN_OPENWAVE_PROXY_NET_ASK,           "x-up-proxy-net-ask" },
+       { FN_OPENWAVE_PROXY_UPLINK_VERSION,    "x-up-proxy-uplink-version" },
+       { FN_OPENWAVE_PROXY_TOD,               "x-up-proxy-tod" },
+       { FN_OPENWAVE_PROXY_BA_ENABLE,         "x-up-proxy-ba-enable" },
+       { FN_OPENWAVE_PROXY_BA_REALM,          "x-up-proxy-ba-realm" },
+       { FN_OPENWAVE_PROXY_REDIRECT_ENABLE,   "x-up-proxy-redirect-enable" },
+       { FN_OPENWAVE_PROXY_REQUEST_URI,       "x-up-proxy-request-uri" },
+       { FN_OPENWAVE_PROXY_REDIRECT_STATUS,   "x-up-proxy-redirect-status" },
+       { FN_OPENWAVE_PROXY_TRANS_CHARSET,     "x-up-proxy-trans-charset" },
+       { FN_OPENWAVE_PROXY_LINGER,            "x-up-proxy-linger" },
+       { FN_OPENWAVE_PROXY_CLIENT_ID,         "x-up-proxy-client-id" },
+       { FN_OPENWAVE_PROXY_ENABLE_TRUST,      "x-up-proxy-enable-trust" },
+       { FN_OPENWAVE_PROXY_TRUST_OLD,         "x-up-proxy-trust-old" },
+       { FN_OPENWAVE_PROXY_TRUST,             "x-up-proxy-trust" },
+       { FN_OPENWAVE_PROXY_BOOKMARK,          "x-up-proxy-bookmark" },
+       { FN_OPENWAVE_DEVCAP_GUI,              "x-up-devcap-gui" },
+       { 0,                                   NULL }
+};     
+
 
 static const value_string vals_field_names[] = {
        { FN_ACCEPT,               "Accept" },
@@ -388,6 +519,10 @@ static const value_string vals_field_names[] = {
        { FN_SET_COOKIE,           "Set-Cookie" },
        { FN_COOKIE,               "Cookie" },
        { FN_ENCODING_VERSION,     "Encoding-Version" },
+       { FN_PROFILE_WARNING14,    "Profile-Warning (encoding 1.4)" },
+       { FN_CONTENT_DISPOSITION14,"Content-Disposition (encoding 1.4)" },
+       { FN_X_WAP_SECURITY,       "X-WAP-Security" },
+       { FN_CACHE_CONTROL14,      "Cache-Control (encoding 1.4)" },
        { 0,                       NULL }
 };     
 
@@ -513,6 +648,28 @@ static const value_string vals_content_types[] = {
        { 0x32, "application/vnd.wap.coc" },
        { 0x33, "application/vnd.wap.multipart.related" },
        { 0x34, "application/vnd.wap.sia" },
+       { 0x35, "text/vnd.wap.connectivity-xml" },
+       { 0x36, "application/vnd.wap.connectivity-wbxml" },
+       { 0x37, "application/pkcs7-mime" },
+       { 0x38, "application/vnd.wap.hashed-certificate" },
+       { 0x39, "application/vnd.wap.signed-certificate" },
+       { 0x3A, "application/vnd.wap.cert-response" },
+       { 0x3B, "application/xhtml+xml" },
+       { 0x3C, "application/wml+xml" },
+       { 0x3D, "text/css" },
+       { 0x3E, "application/vnd.wap.mms-message" },
+       { 0x3F, "application/vnd.wap.rollover-certificate" },
+       { 0x201, "application/vnd.uplanet.cachop-wbxml" },
+       { 0x202, "application/vnd.uplanet.signal" },
+       { 0x203, "application/vnd.uplanet.alert-wbxml" },
+       { 0x204, "application/vnd.uplanet.list-wbxml" },
+       { 0x205, "application/vnd.uplanet.listcmd-wbxml" },
+       { 0x206, "application/vnd.uplanet.channel-wbxml" },
+       { 0x207, "application/vnd.uplanet.provisioning-status-uri" },
+       { 0x208, "x-wap.multipart/vnd.uplanet.header-set" },
+       { 0x209, "application/vnd.uplanet.bearer-choice-wbxml" },
+       { 0x20A, "application/vnd.phonecom.mmc-wbxml" },
+       { 0x20B, "application/vnd.nokia.syncset+wbxml" },
        { 0x00, NULL }
 };
 
@@ -549,7 +706,9 @@ static const value_string vals_languages[] = {
        { 0x1E, "Persian (fa)" },
        { 0x1F, "Finnish (fi)" },
        { 0x20, "Fiji (fj)" },
+       { 0x21, "Urdu (ur)" },
        { 0x22, "French (fr)" },
+       { 0x23, "Uzbek (uz)" },
        { 0x24, "Irish (ga)" },
        { 0x25, "Scots Gaelic (gd)" },
        { 0x26, "Galician (gl)" },
@@ -561,7 +720,30 @@ static const value_string vals_languages[] = {
        { 0x2C, "Croatian (hr)" },
        { 0x2D, "Hungarian (hu)" },
        { 0x2E, "Armenian (hy)" },
+       { 0x2F, "Vietnamese (vi)" },
        { 0x30, "Indonesian (formerly in) (id)" },
+       { 0x31, "Wolof (wo)" },
+       { 0x32, "Xhosa (xh)" },
+       { 0x33, "Icelandic (is)" },
+       { 0x34, "Italian (it)" },
+       { 0x35, "Yoruba (yo)" },
+       { 0x36, "Japanese (ja)" },
+       { 0x37, "Javanese (jw)" },
+       { 0x38, "Georgian (ka)" },
+       { 0x39, "Kazakh (kk)" },
+       { 0x3A, "Zhuang (za)" },
+       { 0x3B, "Cambodian (km)" },
+       { 0x3C, "Kannada (kn)" },
+       { 0x3D, "Korean (ko)" },
+       { 0x3E, "Kashmiri (ks)" },
+       { 0x3F, "Kurdish (ku)" },
+       { 0x40, "Kirghiz (ky)" },
+       { 0x41, "Chinese (zh)" },
+       { 0x42, "Lingala (ln)" },
+       { 0x43, "Laothian (lo)" },
+       { 0x44, "Lithuanian (lt)" },
+       { 0x45, "Latvian, Lettish (lv)" },
+       { 0x46, "Malagasy (mg)" },
        { 0x47, "Maori (mi)" },
        { 0x48, "Macedonian (mk)" },
        { 0x49, "Malayalam (ml)" },
@@ -571,6 +753,7 @@ static const value_string vals_languages[] = {
        { 0x4D, "Malay (ms)" },
        { 0x4E, "Maltese (mt)" },
        { 0x4F, "Burmese (my)" },
+       { 0x50, "Ukrainian (uk)" },
        { 0x51, "Nepali (ne)" },
        { 0x52, "Dutch (nl)" },
        { 0x53, "Norwegian (no)" },
@@ -582,6 +765,7 @@ static const value_string vals_languages[] = {
        { 0x59, "Pashto, Pushto (ps)" },
        { 0x5A, "Portuguese (pt)" },
        { 0x5B, "Quechua (qu)" },
+       { 0x5C, "Zulu (zu)" },
        { 0x5D, "Kirundi (rn)" },
        { 0x5E, "Romanian (ro)" },
        { 0x5F, "Russian (ru)" },
@@ -608,10 +792,26 @@ static const value_string vals_languages[] = {
        { 0x74, "Tajik (tg)" },
        { 0x75, "Thai (th)" },
        { 0x76, "Tigrinya (ti)" },
+       { 0x77, "Turkmen (tk)" },
+       { 0x78, "Tagalog (tl)" },
+       { 0x79, "Setswana (tn)" },
+       { 0x7A, "Tonga (to)" },
+       { 0x7B, "Turkish (tr)" },
+       { 0x7C, "Tsonga (ts)" },
+       { 0x7D, "Tatar (tt)" },
+       { 0x7E, "Twi (tw)" },
+       { 0x7F, "Uighur (ug)" },
        { 0x81, "Nauru (na)" },
        { 0x82, "Faeroese (fo)" },
        { 0x83, "Frisian (fy)" },
        { 0x84, "Interlingua (ia)" },
+       { 0x85, "Volapuk (vo)" },
+       { 0x86, "Interlingue (ie)" },
+       { 0x87, "Inupiak (ik)" },
+       { 0x88, "Yiddish (formerly ji) (yi)" },
+       { 0x89, "Inuktitut (iu)" },
+       { 0x8A, "Greenlandic (kl)" },
+       { 0x8B, "Latin (la)" },
        { 0x8C, "Rhaeto-Romance (rm)" },
        { 0x00, NULL }
 };
@@ -651,6 +851,11 @@ static const value_string vals_cache_control[] = {
        { 0x00,             NULL }
 };
 
+static const value_string vals_connection[] = {
+       { 0x00, "Close" },
+       { 0x00, NULL }
+};
+
 static const value_string vals_transfer_encoding[] = {
        { 0x00, "Chunked" },
        { 0x00, NULL }
@@ -684,23 +889,23 @@ static const true_false_string yes_no_truth = {
 enum {
        RESERVED                = 0x00,
        CONNECT                 = 0x01,
-       CONNECTREPLY    = 0x02,
+       CONNECTREPLY            = 0x02,
        REDIRECT                = 0x03,                 /* No sample data */
        REPLY                   = 0x04,
        DISCONNECT              = 0x05,
        PUSH                    = 0x06,                 /* No sample data */
-       CONFIRMEDPUSH   = 0x07,                 /* No sample data */
+       CONFIRMEDPUSH           = 0x07,                 /* No sample data */
        SUSPEND                 = 0x08,                 /* No sample data */
        RESUME                  = 0x09,                 /* No sample data */
 
-       GET                             = 0x40,
+       GET                     = 0x40,
        OPTIONS                 = 0x41,                 /* No sample data */
        HEAD                    = 0x42,                 /* No sample data */
        DELETE                  = 0x43,                 /* No sample data */
        TRACE                   = 0x44,                 /* No sample data */
 
        POST                    = 0x60,
-       PUT                             = 0x61,                 /* No sample data */
+       PUT                     = 0x61,                 /* No sample data */
 };
 
 typedef enum {
@@ -709,7 +914,10 @@ typedef enum {
        VALUE_IN_LEN,
 } value_type_t;
 
-static void add_uri (proto_tree *, tvbuff_t *, guint, guint);
+static dissector_table_t wsp_dissector_table;
+static heur_dissector_list_t heur_subdissector_list;
+
+static void add_uri (proto_tree *, packet_info *, tvbuff_t *, guint, guint);
 static void add_headers (proto_tree *, tvbuff_t *);
 static int add_well_known_header (proto_tree *, tvbuff_t *, int, guint8);
 static int add_unknown_header (proto_tree *, tvbuff_t *, int, guint8);
@@ -724,22 +932,30 @@ static void add_accept_ranges_header (proto_tree *, tvbuff_t *, int,
 static void add_cache_control_header (proto_tree *, tvbuff_t *, int,
     tvbuff_t *, value_type_t, int);
 static int add_cache_control_field_name (proto_tree *, tvbuff_t *, int, guint);
+static void add_connection_header (proto_tree *, tvbuff_t *, int,
+    tvbuff_t *, value_type_t, int);
 static void add_content_type_value (proto_tree *, tvbuff_t *, int, int,
     tvbuff_t *, value_type_t, int, int, int, guint *, const char **);
-static guint add_content_type (proto_tree *, tvbuff_t *, guint, guint *,
-    const char **);
+static void add_wap_application_id_header (proto_tree *, tvbuff_t *, int,
+    tvbuff_t *, value_type_t, int);
+static void add_integer_value_header_common (proto_tree *, tvbuff_t *, int,
+    tvbuff_t *, value_type_t, int, int, guint8, const value_string *);
 static void add_integer_value_header (proto_tree *, tvbuff_t *, int,
     tvbuff_t *, value_type_t, int, int, guint8);
+static void add_string_value_header_common (proto_tree *, tvbuff_t *, int,
+    tvbuff_t *, value_type_t, int, int, guint8, const value_string *);
 static void add_string_value_header (proto_tree *, tvbuff_t *, int,
     tvbuff_t *, value_type_t, int, int, guint8);
+static void add_quoted_string_value_header (proto_tree *, tvbuff_t *, int,
+    tvbuff_t *, value_type_t, int, int, guint8);
 static void add_date_value_header (proto_tree *, tvbuff_t *, int,
     tvbuff_t *, value_type_t, int, int, guint8);
 static int add_parameter (proto_tree *, tvbuff_t *, int);
-static void add_untyped_parameter (proto_tree *, tvbuff_t *, int, int);
-static void add_parameter_charset (proto_tree *, tvbuff_t *, int, int);
-static void add_parameter_type (proto_tree *, tvbuff_t *, int, int);
-static void add_parameter_text (proto_tree *, tvbuff_t *, int, int, int,
-    const char *paramName);
+static int add_untyped_parameter (proto_tree *, tvbuff_t *, int, int);
+static int add_parameter_charset (proto_tree *, tvbuff_t *, int, int);
+static int add_constrained_encoding (proto_tree *, tvbuff_t *, int, int);
+static int add_parameter_type (proto_tree *, tvbuff_t *, int, int);
+static int add_parameter_text (proto_tree *, tvbuff_t *, int, int, int, const char *);
 static void add_post_data (proto_tree *, tvbuff_t *, guint, const char *);
 static void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
 static void add_pragma_header (proto_tree *, tvbuff_t *, int, tvbuff_t *,
@@ -750,15 +966,23 @@ static void add_warning_header (proto_tree *, tvbuff_t *, int, tvbuff_t *,
     value_type_t, int);
 static void add_accept_application_header (proto_tree *, tvbuff_t *, int,
     tvbuff_t *, value_type_t, int);
-static void add_capabilities (proto_tree *tree, tvbuff_t *tvb);
+static void add_capabilities (proto_tree *tree, tvbuff_t *tvb, int type);
+static void add_capability_vals(tvbuff_t *, gboolean, int, guint, guint, char *, size_t);
 static value_type_t get_value_type_len (tvbuff_t *, int, guint *, int *, int *);
 static guint get_uintvar (tvbuff_t *, guint, guint);
 static gint get_integer (tvbuff_t *, guint, guint, value_type_t, guint *);
 
+static int add_well_known_openwave_header (proto_tree *, tvbuff_t *, int, guint8);
+static void add_openwave_integer_value_header (proto_tree *, tvbuff_t *, int,
+    tvbuff_t *, value_type_t, int, int, guint8);
+static void add_openwave_string_value_header (proto_tree *, tvbuff_t *, int,
+    tvbuff_t *, value_type_t, int, int, guint8);
+
+
 /* Code to actually dissect the packets */
 static void
 dissect_redirect(tvbuff_t *tvb, int offset, packet_info *pinfo,
-    proto_tree *tree, dissector_t dissector)
+    proto_tree *tree, dissector_handle_t dissector_handle)
 {
        guint8 flags;
        proto_item *ti;
@@ -881,10 +1105,9 @@ dissect_redirect(tvbuff_t *tvb, int offset, packet_info *pinfo,
                            PT_UDP, port_num, 0, NO_PORT_B);
                        if (conv == NULL) {
                                conv = conversation_new(&redir_address,
-                                   &pinfo->dst, PT_UDP, port_num, 0,
-                                   NULL, NO_PORT2);
+                                   &pinfo->dst, PT_UDP, port_num, 0, NO_PORT2);
                        }
-                       conversation_set_dissector(conv, dissector);
+                       conversation_set_dissector(conv, dissector_handle);
                        break;
 
                case BT_IPv6:
@@ -916,10 +1139,9 @@ dissect_redirect(tvbuff_t *tvb, int offset, packet_info *pinfo,
                            PT_UDP, port_num, 0, NO_PORT_B);
                        if (conv == NULL) {
                                conv = conversation_new(&redir_address,
-                                   &pinfo->dst, PT_UDP, port_num, 0,
-                                   NULL, NO_PORT2);
+                                   &pinfo->dst, PT_UDP, port_num, 0, NO_PORT2);
                        }
-                       conversation_set_dissector(conv, dissector);
+                       conversation_set_dissector(conv, dissector_handle);
                        break;
 
                unknown_address_type:
@@ -940,9 +1162,8 @@ dissect_redirect(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
 static void
 dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
-    dissector_t dissector, gboolean is_connectionless)
+    dissector_handle_t dissector_handle, gboolean is_connectionless)
 {
-       frame_data *fdata = pinfo->fd;
        int offset = 0;
 
        guint8 pdut;
@@ -970,12 +1191,6 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
    it, if possible, summarize what's in the packet, so that a user looking
    at the list of packets can tell what type of packet it is. */
     
-       /* Clear the Info column before we fetch anything from the packet */
-       if (check_col(fdata, COL_INFO))
-       {
-               col_clear(fdata, COL_INFO);
-       }
-
        /* Connection-less mode has a TID first */
        if (is_connectionless)
        {
@@ -986,17 +1201,17 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        pdut = tvb_get_guint8 (tvb, offset);
 
        /* Develop the string to put in the Info column */
-       if (check_col(fdata, COL_INFO))
+       if (check_col(pinfo->cinfo, COL_INFO))
        {
-               col_add_fstr(fdata, COL_INFO, "WSP %s",
+               col_append_fstr(pinfo->cinfo, COL_INFO, "WSP %s",
                        val_to_str (pdut, vals_pdu_type, "Unknown PDU type (0x%02x)"));
        };
 
 /* In the interest of speed, if "tree" is NULL, don't do any work not
    necessary to generate protocol tree items. */
        if (tree) {
-               ti = proto_tree_add_item(tree, proto_wsp, tvb, 0,
-                   tvb_length(tvb), bo_little_endian);
+               ti = proto_tree_add_item(tree, proto_wsp, tvb, 0, -1,
+                   bo_little_endian);
                wsp_tree = proto_item_add_subtree(ti, ett_wsp);
 
 /* Code to process the packet goes here */
@@ -1027,69 +1242,49 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        switch (pdut)
        {
                case CONNECT:
+               case CONNECTREPLY:
+               case RESUME:
                        if (tree) {
-                               ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
-                               ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
-                               offset++;
-                               capabilityStart = offset;
-                               count = 0;      /* Initialise count */
-                               capabilityLength = tvb_get_guintvar (tvb, offset, &count);
-                               offset += count;
-                               ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
-
-                               headerStart = offset;
-                               count = 0;      /* Initialise count */
-                               headerLength = tvb_get_guintvar (tvb, offset, &count);
-                               offset += count;
-                               ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
-                               if (capabilityLength > 0)
-                               {
-                                       tmp_tvb = tvb_new_subset (tvb, offset, capabilityLength, capabilityLength);
-                                       add_capabilities (wsp_tree, tmp_tvb);
-                                       offset += capabilityLength;
-                               }
-
-                               if (headerLength > 0)
+                               if (pdut == CONNECT)
                                {
-                                       tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
-                                       add_headers (wsp_tree, tmp_tvb);
+                                       ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
+                                       ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
+                                       offset++;
+                               } else {
+                                       count = 0;      /* Initialise count */
+                                       value = tvb_get_guintvar (tvb, offset, &count);
+                                       ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
+                                       offset += count;
                                }
-                       }
-
-                       break;
-
-               case CONNECTREPLY:
-                       if (tree) {
-                               count = 0;      /* Initialise count */
-                               value = tvb_get_guintvar (tvb, offset, &count);
-                               ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
-                               offset += count;
-
                                capabilityStart = offset;
                                count = 0;      /* Initialise count */
                                capabilityLength = tvb_get_guintvar (tvb, offset, &count);
                                offset += count;
                                ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
 
-                               headerStart = offset;
-                               count = 0;      /* Initialise count */
-                               headerLength = tvb_get_guintvar (tvb, offset, &count);
-                               offset += count;
-                               ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
+                               if (pdut != RESUME)
+                               {
+                                       count = 0;      /* Initialise count */
+                                       headerLength = tvb_get_guintvar (tvb, offset, &count);
+                                       ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset,count,headerLength);
+                                       offset += count;
+                                       capabilityStart = offset;
+                                       headerStart = capabilityStart + capabilityLength;
+                               } else {
+                                               /* Resume computes the headerlength by remaining bytes */
+                                       capabilityStart = offset;
+                                       headerStart = capabilityStart + capabilityLength;
+                                       headerLength = tvb_reported_length_remaining (tvb, headerStart);
+                               }
                                if (capabilityLength > 0)
                                {
                                        tmp_tvb = tvb_new_subset (tvb, offset, capabilityLength, capabilityLength);
-                                       add_capabilities (wsp_tree, tmp_tvb);
+                                       add_capabilities (wsp_tree, tmp_tvb, pdut);
                                        offset += capabilityLength;
                                }
 
                                if (headerLength > 0)
                                {
-
-                                       /*
-                                       ti = proto_tree_add_item (wsp_tree, hf_wsp_headers_section,tvb,offset,headerLength,bo_little_endian);
-                                       wsp_headers = proto_item_add_subtree( ti, ett_headers );
-                                       */
                                        tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
                                        add_headers (wsp_tree, tmp_tvb);
                                }
@@ -1099,10 +1294,11 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
                case REDIRECT:
                        dissect_redirect(tvb, offset, pinfo, wsp_tree,
-                         dissector);
+                         dissector_handle);
                        break;
 
                case DISCONNECT:
+               case SUSPEND:
                        if (tree) {
                                count = 0;      /* Initialise count */
                                value = tvb_get_guintvar (tvb, offset, &count);
@@ -1111,12 +1307,12 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        break;
 
                case GET:
-                       if (tree) {
-                               count = 0;      /* Initialise count */
+                       count = 0;      /* Initialise count */
                                /* Length of URI and size of URILen field */
-                               value = tvb_get_guintvar (tvb, offset, &count);
-                               nextOffset = offset + count;
-                               add_uri (wsp_tree, tvb, offset, nextOffset);
+                       value = tvb_get_guintvar (tvb, offset, &count);
+                       nextOffset = offset + count;
+                       add_uri (wsp_tree, pinfo, tvb, offset, nextOffset);
+                       if (tree) {
                                offset += (value+count); /* VERIFY */
                                tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
                                add_headers (wsp_tree, tmp_tvb);
@@ -1124,16 +1320,16 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        break;
 
                case POST:
+                       uriStart = offset;
+                       count = 0;      /* Initialise count */
+                       uriLength = tvb_get_guintvar (tvb, offset, &count);
+                       headerStart = uriStart+count;
+                       count = 0;      /* Initialise count */
+                       headersLength = tvb_get_guintvar (tvb, headerStart, &count);
+                       offset = headerStart + count;
+
+                       add_uri (wsp_tree, pinfo, tvb, uriStart, offset);
                        if (tree) {
-                               uriStart = offset;
-                               count = 0;      /* Initialise count */
-                               uriLength = tvb_get_guintvar (tvb, offset, &count);
-                               headerStart = uriStart+count;
-                               count = 0;      /* Initialise count */
-                               headersLength = tvb_get_guintvar (tvb, headerStart, &count);
-                               offset = headerStart + count;
-
-                               add_uri (wsp_tree, tvb, uriStart, offset);
                                offset += uriLength;
 
                                ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headersLength);
@@ -1162,13 +1358,20 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                add_post_data (wsp_tree, tmp_tvb,
                                    contentType, contentTypeStr);
                        }
+                       if (tvb_reported_length_remaining(tvb, headerStart + count + uriLength + headersLength) > 0)
+                       {
+                               tmp_tvb = tvb_new_subset (tvb, headerStart + count + uriLength + headersLength, -1, -1);
+                               if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
+                                       dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
+                       }
                        break;
 
                case REPLY:
+                       count = 0;      /* Initialise count */
+                       headersLength = tvb_get_guintvar (tvb, offset+1, &count);
+                       headerStart = offset + count + 1;
                        if (tree) {
                                ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
-                               count = 0;      /* Initialise count */
-                               headersLength = tvb_get_guintvar (tvb, offset+1, &count);
                                nextOffset = offset + 1 + count;
                                ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,headersLength);
 
@@ -1188,16 +1391,65 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                        tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
                                        add_headers (wsp_tree, tmp_tvb);
                                }
-                               offset += count+headerLength+1;
+                               offset += count+headersLength+1;
 
                                /* TODO: Data - decode WMLC */
                                /* Runs from offset+1+count+headerLength+1 to end of frame */
-                               if (offset < tvb_reported_length (tvb))
+                               if (tvb_reported_length_remaining (tvb, offset) > 0)
+                               {
+                                       ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,-1,bo_little_endian);
+                               }
+                       }
+                       if (tvb_reported_length_remaining(tvb, headerStart + headersLength) > 0)
+                       {
+                               tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength, -1, -1);
+                               if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
+                                       dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
+                       }
+                       break;
+
+               case PUSH:
+               case CONFIRMEDPUSH:
+                       count = 0;      /* Initialise count */
+                       headersLength = tvb_get_guintvar (tvb, offset, &count);
+                       headerStart = offset + count;
+
+                       if (tree) {
+                               ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset,count,headersLength);
+
+                               if (headersLength == 0)
+                                       break;
+
+                               offset += count;
+                               contentTypeStart = offset;
+                               nextOffset = add_content_type (wsp_tree,
+                                   tvb, offset, &contentType,
+                                   &contentTypeStr);
+
+                               /* Add headers subtree that will hold the headers fields */
+                               /* Runs from nextOffset for headersLength-(length of content-type field)*/
+                               headerLength = headersLength-(nextOffset-contentTypeStart);
+                               if (headerLength > 0)
+                               {
+                                       tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
+                                       add_headers (wsp_tree, tmp_tvb);
+                               }
+                               offset += headersLength;
+
+                               /* Push DATA */
+                               if (tvb_reported_length_remaining (tvb, offset) > 0)
                                {
-                                       ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,tvb_length_remaining(tvb, offset),bo_little_endian);
+                                       ti = proto_tree_add_item (wsp_tree, hf_wsp_push_data,tvb,offset,-1,bo_little_endian);
                                }
                        }
+                       if (tvb_reported_length_remaining(tvb, headerStart + headersLength) > 0)
+                       {
+                               tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength, -1, -1);
+                               if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
+                                       dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
+                       }
                        break;
+
        }
 }
 
@@ -1208,10 +1460,12 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 static void
 dissect_wsp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       if (check_col(pinfo->fd, COL_PROTOCOL))
-               col_set_str(pinfo->fd, COL_PROTOCOL, "WSP" );
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "WSP" );
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_clear(pinfo->cinfo, COL_INFO);
 
-       dissect_wsp_common(tvb, pinfo, tree, dissect_wsp_fromudp, TRUE);
+       dissect_wsp_common(tvb, pinfo, tree, wsp_fromudp_handle, TRUE);
 }
 
 /*
@@ -1225,7 +1479,7 @@ dissect_wsp_fromwap_co(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        /*
         * XXX - what about WTLS->WTP->WSP?
         */
-       dissect_wsp_common(tvb, pinfo, tree, dissect_wtp_fromudp, FALSE);
+       dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, FALSE);
 }
 
 /*
@@ -1239,35 +1493,35 @@ dissect_wsp_fromwap_cl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        /*
         * XXX - what about WTLS->WSP?
         */
-       dissect_wsp_common(tvb, pinfo, tree, dissect_wtp_fromudp, TRUE);
+       if (check_col(pinfo->cinfo, COL_INFO))
+       {
+               col_clear(pinfo->cinfo, COL_INFO);
+       }
+       dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, TRUE);
 }
 
 static void
-add_uri (proto_tree *tree, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
+add_uri (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
 {
        proto_item *ti;
-       guint8 terminator = 0;
        char *newBuffer;
 
        guint count = 0;
        guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
 
-       ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
-
-       /* If string doesn't end with a 0x00, we need to add one to be on the safe side */
-       terminator = tvb_get_guint8 (tvb, URIOffset+uriLen-1);
-       if (terminator != 0)
-       {
-               newBuffer = g_malloc (uriLen+1);
-               strncpy (newBuffer, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
-               newBuffer[uriLen] = 0;
-               ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer);
-               g_free (newBuffer);
-       }
-       else
-       {
-               ti = proto_tree_add_item (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,bo_little_endian);
-       }
+       if (tree)
+               ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
+
+       newBuffer = g_malloc (uriLen+2);
+       newBuffer[0] = ' ';  /* This is for COL_INFO */
+       strncpy (newBuffer+1, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
+       newBuffer[uriLen+1] = 0;
+       if (tree)
+               ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer+1);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_str(pinfo->cinfo, COL_INFO, newBuffer);
+       };
+       g_free (newBuffer);
 }
 
 static void
@@ -1277,7 +1531,7 @@ add_headers (proto_tree *tree, tvbuff_t *tvb)
        proto_tree *wsp_headers;
        guint offset = 0;
        guint headersLen = tvb_reported_length (tvb);
-       guint8 headerStart = 0;
+       guint headerStart = 0;
        guint peek = 0;
        guint pageCode = 1;
 
@@ -1344,15 +1598,22 @@ add_headers (proto_tree *tree, tvbuff_t *tvb)
                         * Well-known-header; the lower 7 bits of "peek"
                         * are the header code.
                         */
-                       if (pageCode == 1)
-                       {
+                       switch (pageCode) {
+                       case 1:
                                offset = add_well_known_header (wsp_headers,
                                    tvb, headerStart, peek & 0x7F);
-                       }
-                       else 
-                       {
+                               break;
+
+                       case 2:
+                       case 16:
+                               offset = add_well_known_openwave_header (wsp_headers,
+                                   tvb, headerStart, peek & 0x7F);
+                               break;
+
+                       default:
                                offset = add_unknown_header (wsp_headers,
                                    tvb, headerStart, peek & 0x7F);
+                               break;
                        }
                }
        }
@@ -1459,14 +1720,21 @@ add_well_known_header (proto_tree *tree, tvbuff_t *tvb, int offset,
                break;
 
        case FN_CACHE_CONTROL_DEP:      /* Cache-Control */
+       case FN_CACHE_CONTROL:
+       case FN_CACHE_CONTROL14:
                /*
-                * XXX - should both encoding versions 1.1 and
-                * 1.3 be handled this way?
+                * XXX - is the only difference in the three different
+                * versions (1.1, 1.3, 1.4) really only S_MAXAGE?
                 */
                add_cache_control_header (tree, header_buff, headerLen,
                    value_buff, valueType, valueLen);
                break;
                                
+       case FN_CONNECTION:     /* Connection */
+               add_connection_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen);
+               break;
+
        case FN_CONTENT_LENGTH:         /* Content-Length */
                add_integer_value_header (tree, header_buff, headerLen,
                    value_buff, valueType, valueLen,
@@ -1560,6 +1828,17 @@ add_well_known_header (proto_tree *tree, tvbuff_t *tvb, int offset,
                    hf_wsp_header_profile, headerType);
                break;
 
+       case FN_X_WAP_APPLICATION_ID:   /* X-Wap-Application-Id */
+               add_wap_application_id_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen);
+               break;
+
+       case FN_CONTENT_ID:             /* Content-ID   */
+               add_quoted_string_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_content_ID, headerType);
+               break;
+
        default:
                proto_tree_add_text (tree, header_buff, 0, headerLen,
                    "Unsupported Header: %s",
@@ -1569,17 +1848,22 @@ add_well_known_header (proto_tree *tree, tvbuff_t *tvb, int offset,
        return offset;
 }
 
+
 static int
-add_unknown_header (proto_tree *tree, tvbuff_t *tvb, int offset,
+add_well_known_openwave_header (proto_tree *tree, tvbuff_t *tvb, int offset,
     guint8 headerType)
 {
        int headerStart;
-       int valueStart;
        value_type_t valueType;
        int headerLen;
        guint valueLen;
-       int valueOffset;
+       int valueStart;
+       tvbuff_t *header_buff;
+       tvbuff_t *value_buff;
 
+#ifdef DEBUG
+       fprintf (stderr, "dissect_wsp: Got Openwave header 0x%02x\n", headerType);
+#endif
        headerStart = offset;
 
        /*
@@ -1587,137 +1871,370 @@ add_unknown_header (proto_tree *tree, tvbuff_t *tvb, int offset,
         */
        offset++;
 
-       valueStart = offset;
-
        /*
         * Get the value type and length (or, if the type is VALUE_IN_LEN,
         * meaning the value is a Short-integer, get the value type
         * and the value itself).
         */ 
-       valueType = get_value_type_len (tvb, valueStart, &valueLen,
-           &valueOffset, &offset);
+       valueType = get_value_type_len (tvb, offset, &valueLen,
+           &valueStart, &offset);
        headerLen = offset - headerStart;
 
-       proto_tree_add_text (tree, tvb, headerStart, headerLen,
-                      "Unsupported Header (0x%02X)", headerType);
-       return offset;
-}
-
-static int
-add_application_header (proto_tree *tree, tvbuff_t *tvb, int offset)
-{
-       int startOffset;
-       gint tokenLen;
-       const guint8 *token;
-       value_type_t valueType;
-       int subvalueLen;
-       int subvalueOffset;
-       guint secs;
-       struct timeval timeValue;
-       int asvOffset;
-       gint stringLen;
+       /*
+        * Get a tvbuff for the entire header.
+        * XXX - cut the actual length short so that it doesn't run
+        * past the actual length of tvb.
+        */
+       header_buff = tvb_new_subset (tvb, headerStart, headerLen,
+           headerLen);
 
-       startOffset = offset;
-       tokenLen = tvb_strnlen(tvb, startOffset, -1);
-       if (tokenLen == -1) {
+       /*
+        * If the value wasn't in the length, get a tvbuff for the value.
+        * XXX - can valueLen be 0?
+        * XXX - cut the actual length short so that it doesn't run
+        * past the actual length of tvb.
+        */
+       if (valueType != VALUE_IN_LEN) {
+               value_buff = tvb_new_subset (tvb, valueStart, valueLen,
+                   valueLen);
+       } else {
                /*
-                * Make the length (not including the null byte at the
-                * end) the remaining reported length of the tvbuffer;
-                * this should cause us to throw the correct exception
-                * when we try to do a tvb_get_ptr starting at that
-                * offset with that length + 1, which is what we want
-                * (we ran past the end of the buffer trying
-                * to find the End-of-string).
+                * XXX - when the last dissector is tvbuffified,
+                * so that NULL is no longer a valid tvb pointer
+                * value in "proto_tree_add" calls, just
+                * set "value_buff" to NULL.
+                *
+                * XXX - can we already do that?  I.e., will that
+                * cause us always to crash if we mistakenly try
+                * to fetch the value of a VALUE_IN_LEN item?
                 */
-               tokenLen = tvb_reported_length_remaining (tvb, startOffset);
+               value_buff = tvb_new_subset (tvb, headerStart, 0, 0);
        }
-       tokenLen++;     /* include the terminating null byte */
-       token = tvb_get_ptr (tvb, startOffset, tokenLen);
-       offset += tokenLen;
 
-       /*
-        * Special case header "X-WAP.TOD" that is sometimes followed
-        * by a 4-byte date value.
-        *
-        * XXX - according to the 4-May-2000 WSP spec, X-Wap-Tod is
-        * encoded as a well known header, with a code of 0x3F.
-        */
-       if (tokenLen == 10 && strncasecmp ("x-wap.tod", token, 9) == 0)
-       {
-               valueType = get_value_type_len (tvb, offset,
-                   &subvalueLen, &subvalueOffset, &offset);
-               if (get_integer (tvb, subvalueOffset, subvalueLen,
-                   valueType, &secs) == 0)
-               {
-                       /*
-                        * Fill in the "struct timeval", and add it to the
-                        * protocol tree.
-                        * Note: this will succeed even if it's a Short-integer.
-                        * A Short-integer would work, but, as the time values
-                        * are UNIX seconds-since-the-Epoch value, and as
-                        * there weren't WAP phones or Web servers back in
-                        * late 1969/early 1970, they're unlikely to be used.
-                        */
-                       timeValue.tv_sec = secs;
-                       timeValue.tv_usec = 0;
-                       proto_tree_add_time (tree, hf_wsp_header_x_wap_tod,
-                           tvb, startOffset, offset - startOffset, &timeValue);
-               }
-               else
-               {
-                       proto_tree_add_text (tree, tvb, startOffset,
-                           offset - startOffset,
-                           "%s: invalid date value", token);
-               }
-       }
-       else
-       {
-               asvOffset = offset;
-               stringLen = tvb_strnlen (tvb, asvOffset, -1);
-               if (stringLen == -1) {
-                       /*
-                        * Make the length (not including the null byte at the
-                        * end) the remaining reported length of the tvbuffer;
-                        * this should cause us to throw the correct exception
-                        * when we try to do a tvb_get_ptr starting at that
-                        * offset with that length + 1, which is what we want
-                        * (we ran past the end of the buffer trying
-                        * to find the End-of-string).
-                        */
-                       stringLen =
-                           tvb_reported_length_remaining (tvb, asvOffset);
-               }
-               stringLen++;    /* include the terminating null byte */
-               offset += stringLen;
-               proto_tree_add_text (tree, tvb, startOffset,
-                   offset - startOffset,
-                   "%s: %s", token,
-                   tvb_get_ptr (tvb, asvOffset, stringLen));
-       }
-       return offset;
-}
+       switch (headerType) {
 
-static void
-add_accept_header (proto_tree *tree, tvbuff_t *header_buff,
-    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
-    int valueLen)
-{
-       guint contentType;
-       const char *contentTypeStr;
+/*     case FN_OPENWAVE_PROXY_PUSH_ADDR:       / x-up-proxy-push-addr */
+/*             add_openwave_push_address_header (tree, header_buff, headerLen, */
+/*                 value_buff, valueType, valueLen); */
+/*             break; */
 
-       add_content_type_value (tree, header_buff, 0, headerLen, value_buff,
-           valueType, valueLen, hf_wsp_header_accept,
-           hf_wsp_header_accept_str, &contentType, &contentTypeStr);
-}
+       case FN_OPENWAVE_PROXY_PUSH_ACCEPT:     /* x-up-proxy-push-accept */
+               add_accept_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen);
+               break;
 
-static void
-add_accept_xxx_header (proto_tree *tree, tvbuff_t *header_buff,
-    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
-    int valueLen, int hf_numeric, int hf_string,
-    const value_string *vals, const char *unknown_tag)
-{
-       int offset = 0;
-       int subvalueLen;
+       case FN_OPENWAVE_PROXY_PUSH_SEQ:        /* x-up-proxy-push-seq */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_push_seq,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_NOTIFY:          /* x-up-proxy-notify */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_notify,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_OPERATOR_DOMAIN: /* x-up-proxy-operator-domain */
+               add_openwave_string_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_operator_domain, headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_HOME_PAGE:       /* x-up-proxy-home-page */
+               add_openwave_string_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_home_page, headerType);
+               break;
+
+       case FN_OPENWAVE_DEVCAP_HAS_COLOR:      /* x-up-devcap-has-color */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_has_color,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS:   /* x-up-devcap-num-softkeys */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_num_softkeys,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE:   /* x-up-devcap-softkey-size */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_softkey_size,
+                   headerType);
+               break;
+
+/*     case FN_OPENWAVE_DEVCAP_SCREEN_CHARS:   / x-up-devcap-screen-chars */
+/*             add_openwave_integer_value_header (tree, header_buff, headerLen, */
+/*                 value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_screen_chars, */
+/*                 headerType); */
+/*             break; */
+
+/*     case FN_OPENWAVE_DEVCAP_SCREEN_PIXELS:  / x-up-devcap-screen-pixels */
+/*             add_openwave_integer_value_header (tree, header_buff, headerLen, */
+/*                 value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_screen_pixels, */
+/*                 headerType); */
+/*             break; */
+
+/*     case FN_OPENWAVE_DEVCAP_EM_SIZE:        / x-up-devcap-em-size */
+/*             add_openwave_integer_value_header (tree, header_buff, headerLen, */
+/*                 value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_em_size, */
+/*                 headerType); */
+/*             break; */
+
+       case FN_OPENWAVE_DEVCAP_SCREEN_DEPTH:   /* x-up-devcap-screen-depth */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_screen_depth,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_DEVCAP_IMMED_ALERT:    /* x-up-devcap-immed-alert */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_immed_alert,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_NET_ASK:         /* x-up-proxy-net-ask */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_net_ask,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_UPLINK_VERSION:          /* x-up-proxy-uplink-version */
+               add_openwave_string_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_uplink_version, headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_TOD:             /* x-up-proxy-tod */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_tod, headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_BA_ENABLE:               /* x-up-proxy-ba-enable */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_ba_enable, headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_BA_REALM:                /* x-up-proxy-ba-realm */
+               add_openwave_string_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_ba_realm, headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_REDIRECT_ENABLE:         /* x-up-proxy-redirect-enable */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_redirect_enable, headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_REQUEST_URI:             /* x-up-proxy-request-uri */
+               add_openwave_string_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_request_uri, headerType);
+               break;
+
+/*     case FN_OPENWAVE_PROXY_REDIRECT_STATUS:         / x-up-proxy-redirect-status */
+/*             add_openwave_integer_value_header (tree, header_buff, headerLen, */
+/*                 value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_redirect_status, */
+/*                 headerType); */
+/*             break; */
+
+       case FN_OPENWAVE_PROXY_TRANS_CHARSET:           /* x-up-proxy-trans-charset */
+               add_accept_xxx_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_trans_charset,
+                   hf_wsp_header_openwave_proxy_trans_charset_str,
+                   vals_character_sets, "Unknown charset (%u)");
+               break;
+
+       case FN_OPENWAVE_PROXY_LINGER:                  /* x-up-proxy-linger */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_linger,
+                   headerType);
+               break;
+
+/*     case FN_OPENWAVE_PROXY_CLIENT_ID:               / x-up-proxy-client-id */
+/*             add_openwave_string_value_header (tree, header_buff, headerLen, */
+/*                 value_buff, valueType, valueLen, */
+/*                 hf_wsp_header_openwave_proxy_client_id, headerType); */
+/*             break; */
+
+       case FN_OPENWAVE_PROXY_ENABLE_TRUST:            /* x-up-proxy-enable-trust */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_enable_trust,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_TRUST_OLD:               /* x-up-proxy-trust old value */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_trust_old,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_TRUST:                   /* x-up-proxy-trust */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_trust,
+                   headerType);
+               break;
+
+       case FN_OPENWAVE_PROXY_BOOKMARK:                /* x-up-proxy-bookmark */
+               add_openwave_string_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen,
+                   hf_wsp_header_openwave_proxy_bookmark, headerType);
+               break;
+
+       case FN_OPENWAVE_DEVCAP_GUI:                    /* x-up-devcap-gui */
+               add_openwave_integer_value_header (tree, header_buff, headerLen,
+                   value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_gui,
+                   headerType);
+               break;
+
+       default:
+               proto_tree_add_text (tree, header_buff, 0, headerLen,
+                   "Unsupported Openwave Header: %s",
+                   val_to_str (headerType, vals_openwave_field_names, "Unknown (0x%02X)"));
+               break;
+       }
+       return offset;
+}
+
+static void
+add_openwave_push_address_header (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen)
+{
+
+/*     ??? */
+       
+}
+
+
+static int
+add_unknown_header (proto_tree *tree, tvbuff_t *tvb, int offset,
+    guint8 headerType)
+{
+       int headerStart;
+       int valueStart;
+       value_type_t valueType;
+       int headerLen;
+       guint valueLen;
+       int valueOffset;
+
+       headerStart = offset;
+
+       /*
+        * Skip the Short-Integer header type.
+        */
+       offset++;
+
+       valueStart = offset;
+
+       /*
+        * Get the value type and length (or, if the type is VALUE_IN_LEN,
+        * meaning the value is a Short-integer, get the value type
+        * and the value itself).
+        */ 
+       valueType = get_value_type_len (tvb, valueStart, &valueLen,
+           &valueOffset, &offset);
+       headerLen = offset - headerStart;
+
+       proto_tree_add_text (tree, tvb, headerStart, headerLen,
+                      "Unsupported Header (0x%02X)", headerType);
+       return offset;
+}
+
+static int
+add_application_header (proto_tree *tree, tvbuff_t *tvb, int offset)
+{
+       int startOffset;
+       guint tokenSize;
+       const guint8 *token;
+       value_type_t valueType;
+       int subvalueLen;
+       int subvalueOffset;
+       guint secs;
+       nstime_t timeValue;
+       int asvOffset;
+       guint stringSize;
+
+       startOffset = offset;
+       tokenSize = tvb_strsize (tvb, startOffset);
+       token = tvb_get_ptr (tvb, startOffset, tokenSize);
+       offset += tokenSize;
+
+       /*
+        * Special case header "X-WAP.TOD" that is sometimes followed
+        * by a 4-byte date value.
+        *
+        * XXX - according to the 4-May-2000 WSP spec, X-Wap-Tod is
+        * encoded as a well known header, with a code of 0x3F.
+        */
+       if (tokenSize == 10 && strncasecmp ("x-wap.tod", token, 9) == 0)
+       {
+               valueType = get_value_type_len (tvb, offset,
+                   &subvalueLen, &subvalueOffset, &offset);
+               if (get_integer (tvb, subvalueOffset, subvalueLen,
+                   valueType, &secs) == 0)
+               {
+                       /*
+                        * Fill in the "struct timeval", and add it to the
+                        * protocol tree.
+                        * Note: this will succeed even if it's a Short-integer.
+                        * A Short-integer would work, but, as the time values
+                        * are UNIX seconds-since-the-Epoch value, and as
+                        * there weren't WAP phones or Web servers back in
+                        * late 1969/early 1970, they're unlikely to be used.
+                        */
+                       timeValue.secs = secs;
+                       timeValue.nsecs = 0;
+                       proto_tree_add_time (tree, hf_wsp_header_x_wap_tod,
+                           tvb, startOffset, offset - startOffset, &timeValue);
+               }
+               else
+               {
+                       proto_tree_add_text (tree, tvb, startOffset,
+                           offset - startOffset,
+                           "%s: invalid date value", token);
+               }
+       }
+       else
+       {
+               asvOffset = offset;
+               stringSize = tvb_strsize (tvb, asvOffset);
+               offset += stringSize;
+               proto_tree_add_text (tree, tvb, startOffset,
+                   offset - startOffset,
+                   "%s: %s", token,
+                   tvb_get_ptr (tvb, asvOffset, stringSize));
+       }
+       return offset;
+}
+
+static void
+add_accept_header (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen)
+{
+       guint contentType;
+       const char *contentTypeStr;
+
+       add_content_type_value (tree, header_buff, 0, headerLen, value_buff,
+           valueType, valueLen, hf_wsp_header_accept,
+           hf_wsp_header_accept_str, &contentType, &contentTypeStr);
+}
+
+static void
+add_accept_xxx_header (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen, int hf_numeric, int hf_string,
+    const value_string *vals, const char *unknown_tag)
+{
+       int offset = 0;
+       int subvalueLen;
        int subvalueOffset;
        guint value = 0;
        char valString[100];
@@ -1860,7 +2377,7 @@ add_cache_control_header (proto_tree *tree, tvbuff_t *header_buff,
     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
     int valueLen)
 {
-       int offset;
+       int offset = 0;
        int subvalueLen;
        int subvalueOffset;
        guint value;
@@ -1949,6 +2466,7 @@ add_cache_control_header (proto_tree *tree, tvbuff_t *header_buff,
                case MAX_AGE:
                case MAX_STALE:
                case MIN_FRESH:
+               case S_MAXAGE:
                        /*
                         * Get Delta-second-value.
                         */
@@ -2032,6 +2550,53 @@ add_cache_control_field_name (proto_tree *tree, tvbuff_t *value_buff,
        return offset;
 }
 
+static void
+add_connection_header (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen)
+{
+       int offset = 0;
+
+       if (valueType == VALUE_LEN_SUPPLIED)
+       {
+               /*
+                * Invalid.
+                */
+               proto_tree_add_text (tree, header_buff, 0, headerLen,
+                   "Invalid Connection value");
+               return;
+       }
+       if (valueType == VALUE_IS_TEXT_STRING)
+       {
+               /*
+                * Token-text.
+                */
+               proto_tree_add_string (tree,
+                   hf_wsp_header_connection_str,
+                   header_buff, 0, headerLen,
+                   tvb_get_ptr (value_buff, 0, valueLen));
+               return;
+       }
+
+       /*
+        * First byte had the 8th bit set.
+        */
+       if (valueLen == 0) {
+               /*
+                * Close.
+                */
+               proto_tree_add_uint (tree, hf_wsp_header_connection,
+                   header_buff, offset, headerLen, valueLen);
+               return;
+       }
+
+       /*
+        * Invalid.
+        */
+       proto_tree_add_text (tree, header_buff, 0, headerLen,
+           "Invalid Connection value");
+}
+
 static void
 add_pragma_header (proto_tree *tree, tvbuff_t *header_buff,
     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
@@ -2103,7 +2668,7 @@ add_transfer_encoding_header (proto_tree *tree, tvbuff_t *header_buff,
 {
        int offset = 0;
 
-       if (valueType == VALUE_IN_LEN)
+       if (valueType == VALUE_LEN_SUPPLIED)
        {
                /*
                 * Invalid.
@@ -2298,18 +2863,52 @@ add_accept_application_header (proto_tree *tree, tvbuff_t *header_buff,
 }
 
 static void
-add_capabilities (proto_tree *tree, tvbuff_t *tvb)
+add_wap_application_id_header (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen)
+{
+       if (valueType == VALUE_IN_LEN)
+       {
+               /*
+                * Must application-id (the 8th bit was stripped off).
+                */
+               proto_tree_add_uint (tree, hf_wsp_header_wap_application_id,
+                   header_buff, 0, headerLen,
+                   valueLen);  /* valueLen is the value */
+               return;
+       }
+       if (valueType == VALUE_IS_TEXT_STRING)
+       {
+               /*
+                * Token-text.
+                */
+               proto_tree_add_string (tree, hf_wsp_header_wap_application_id_str,
+                   header_buff, 0, headerLen,
+                   tvb_get_ptr (value_buff, 0, valueLen));
+               return;
+       }
+
+       /*
+        * Not valid.
+        */
+       fprintf(stderr, "dissect_wsp: Suprising format of X-Wap-Application-Id\n");
+       return;
+}
+
+static void
+add_capabilities (proto_tree *tree, tvbuff_t *tvb, int type)
 {
        proto_item *ti;
        proto_tree *wsp_capabilities;
        guint offset = 0;
        guint offsetStr = 0;
        guint capabilitiesLen = tvb_reported_length (tvb);
-       guint8 capabilitiesStart = 0;
+       guint capabilitiesStart = 0;
        guint peek = 0;
        guint length = 0;
        guint value = 0;
        guint i;
+       int ret;
        char valString[200];
 
 #ifdef DEBUG
@@ -2365,20 +2964,69 @@ add_capabilities (proto_tree *tree, tvbuff_t *tvb)
                                valString[0]=0;
                                if (value & 0x80)
                                {
-                                       i += snprintf(valString+i,200-1,"%s","(Confirmed push facility) ");
+                                       ret = snprintf(valString+i,200-i,"%s","(Confirmed push facility) ");
+                                       if (ret == -1) {
+                                               /*
+                                                * Some versions of snprintf
+                                                * return -1 if they'd
+                                                * truncate the output.
+                                                */
+                                               goto add_string;
+                                       }
+                                       i += ret;
                                }
                                if (value & 0x40)
                                {
-                                       i += snprintf(valString+i,200-1,"%s","(Push facility) ");
+                                       if (i >= 200) {
+                                               /* No more room. */
+                                               goto add_string;
+                                       }
+                                       ret = snprintf(valString+i,200-i,"%s","(Push facility) ");
+                                       if (ret == -1) {
+                                               /*
+                                                * Some versions of snprintf
+                                                * return -1 if they'd
+                                                * truncate the output.
+                                                */
+                                               goto add_string;
+                                       }
+                                       i += ret;
                                }
                                if (value & 0x20)
                                {
-                                       i += snprintf(valString+i,200-1,"%s","(Session resume facility) ");
+                                       if (i >= 200) {
+                                               /* No more room. */
+                                               goto add_string;
+                                       }
+                                       ret = snprintf(valString+i,200-i,"%s","(Session resume facility) ");
+                                       if (ret == -1) {
+                                               /*
+                                                * Some versions of snprintf
+                                                * return -1 if they'd
+                                                * truncate the output.
+                                                */
+                                               goto add_string;
+                                       }
+                                       i += ret;
                                }
                                if (value & 0x10)
                                {
-                                       i += snprintf(valString+i,200-1,"%s","(Acknowledgement headers) ");
+                                       if (i >= 200) {
+                                               /* No more room. */
+                                               goto add_string;
+                                       }
+                                       ret = snprintf(valString+i,200-i,"%s","(Acknowledgement headers) ");
+                                       if (ret == -1) {
+                                               /*
+                                                * Some versions of snprintf
+                                                * return -1 if they'd
+                                                * truncate the output.
+                                                */
+                                               goto add_string;
+                                       }
+                                       i += ret;
                                }
+                       add_string:
                                proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_protocol_opt, tvb, capabilitiesStart, length+1, valString);
                                break;
                        case 0x03 : /* Method-MOR */ 
@@ -2393,35 +3041,17 @@ add_capabilities (proto_tree *tree, tvbuff_t *tvb)
                        case 0x05 : /* Extended Methods */ 
                                offsetStr = offset;
                                offset++;
-                               i = 0;
-                               while ((offsetStr-capabilitiesStart) <= length)
-                               {
-                                       value = tvb_get_guint8(tvb, offsetStr);
-                                       i += snprintf(valString+i,200-i,"(%d - ",value);
-                                       offsetStr++;
-                                       for (;(valString[i] = tvb_get_guint8(tvb, offsetStr));i++,offsetStr++);
-                                       offsetStr++;
-                                       valString[i++] = ')';
-                                       valString[i++] = ' ';
-                               }
-                               valString[i]=0;
+                               add_capability_vals(tvb, (type == CONNECT),
+                                   offsetStr, length, capabilitiesStart,
+                                   valString, sizeof valString);
                                proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_extended_methods, tvb, capabilitiesStart, length+1, valString);
                                break;
                        case 0x06 : /* Header Code Pages */ 
                                offsetStr = offset;
                                offset++;
-                               i = 0;
-                               while ((offsetStr-capabilitiesStart) <= length)
-                               {
-                                       value = tvb_get_guint8(tvb, offsetStr);
-                                       i += snprintf(valString+i,200-i,"(%d - ",value);
-                                       offsetStr++;
-                                       for (;(valString[i] = tvb_get_guint8(tvb, offsetStr));i++,offsetStr++);
-                                       offsetStr++;
-                                       valString[i++] = ')';
-                                       valString[i++] = ' ';
-                               }
-                               valString[i]=0;
+                               add_capability_vals(tvb, (type == CONNECT),
+                                   offsetStr, length, capabilitiesStart,
+                                   valString, sizeof valString);
                                proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_header_code_pages, tvb, capabilitiesStart, length+1, valString);
                                break;
                        case 0x07 : /* Aliases */
@@ -2431,8 +3061,60 @@ add_capabilities (proto_tree *tree, tvbuff_t *tvb)
                                       "Unsupported Header (0x%02X)", peek & 0x7F);
                                break;
                }
-               offset=capabilitiesStart+length+1;
+               offset=capabilitiesStart+length+1;
+       }
+}
+
+static void
+add_capability_vals(tvbuff_t *tvb, gboolean add_string, int offsetStr,
+    guint length, guint capabilitiesStart, char *valString,
+    size_t valStringSize)
+{
+       guint i;
+       int ret;
+       guint value;
+       guint8 c;
+
+       i = 0;
+       while ((offsetStr-capabilitiesStart) <= length)
+       {
+               value = tvb_get_guint8(tvb, offsetStr);
+               if (i >= valStringSize) {
+                       /* No more room. */
+                       break;
+               }
+               if (add_string)
+               {
+                       ret = snprintf(valString+i,valStringSize-i,
+                           "(%d - ",value);
+               }
+               else
+               {
+                       ret = snprintf(valString+i,valStringSize-i,"(%d) ",
+                           value);
+               }
+               if (ret == -1) {
+                       /*
+                        * Some versions of snprintf return -1
+                        * if they'd truncate the output.
+                        */
+                       break;
+               }
+               i += ret;
+               offsetStr++;
+               if (add_string)
+               {
+                       for (;(c = tvb_get_guint8(tvb, offsetStr))
+                           && i < valStringSize - 1; i++,offsetStr++)
+                               valString[i] = c;
+                       offsetStr++;
+                       if (i < valStringSize - 2) {
+                               valString[i++] = ')';
+                               valString[i++] = ' ';
+                       }
+               }
        }
+       valString[i] = '\0';
 }
 
 static value_type_t
@@ -2442,7 +3124,6 @@ get_value_type_len (tvbuff_t *tvb, int offset, guint *valueLen,
        guint8 peek;
        guint32 len;
        guint count;
-       int stringlen;
 
        /* Get value part of header */
        peek = tvb_get_guint8 (tvb, offset);
@@ -2490,21 +3171,7 @@ get_value_type_len (tvbuff_t *tvb, int offset, guint *valueLen,
 #ifdef DEBUG
                fprintf (stderr, "dissect_wsp: Looking for NUL-terminated string\n");
 #endif
-               stringlen = tvb_strnlen (tvb, offset, -1);
-               if (stringlen == -1) {
-                       /*
-                        * Make the length 1 byte more than the remaining
-                        * reported length of the tvbuffer; this should
-                        * cause us to throw the correct exception
-                        * when we try to make a tvbuff starting at
-                        * offset with that length, which is what we want
-                        * (we ran past the end of the buffer trying
-                        * to find the End-of-string).
-                        */
-                       stringlen =
-                           tvb_reported_length_remaining (tvb, offset) + 1;
-               }
-               len = stringlen + 1;    /* Include NUL in length */
+               len = tvb_strsize (tvb, offset);
                *valueLen = len;        /* Length of value */
                *valueOffset = offset;  /* Offset of value */
                offset += len;          /* Skip the value */
@@ -2659,7 +3326,7 @@ add_content_type_value (proto_tree *tree, tvbuff_t *header_buff,
                offset = add_parameter (parameter_tree, value_buff, offset);
 }
 
-static guint
+guint
 add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset,
     guint *contentTypep, const char **contentTypeStrp)
 {
@@ -2715,6 +3382,27 @@ static void
 add_integer_value_header (proto_tree *tree, tvbuff_t *header_buff,
     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
     int valueLen, int hf_numeric, guint8 headerType)
+{
+       add_integer_value_header_common (tree, header_buff, headerLen,
+           value_buff, valueType, valueLen, hf_numeric, headerType,
+           vals_field_names);
+}
+
+static void
+add_openwave_integer_value_header (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen, int hf_numeric, guint8 headerType)
+{
+       add_integer_value_header_common (tree, header_buff, headerLen,
+           value_buff, valueType, valueLen, hf_numeric, headerType,
+           vals_openwave_field_names);
+}
+
+static void
+add_integer_value_header_common (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen, int hf_numeric, guint8 headerType,
+    const value_string *vals)
 {
        guint value;
 
@@ -2722,7 +3410,7 @@ add_integer_value_header (proto_tree *tree, tvbuff_t *header_buff,
        {
                proto_tree_add_text (tree, header_buff, 0, headerLen,
                    "Invalid %s integer value",
-                   match_strval (headerType, vals_field_names));
+                   match_strval (headerType, vals));
        }
        else
        {
@@ -2735,12 +3423,33 @@ static void
 add_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
     int valueLen, int hf_string, guint8 headerType)
+{
+       add_string_value_header_common (tree, header_buff, headerLen,
+           value_buff, valueType, valueLen, hf_string, headerType,
+           vals_field_names);
+}
+
+static void
+add_openwave_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen, int hf_string, guint8 headerType)
+{
+       add_string_value_header_common (tree, header_buff, headerLen,
+           value_buff, valueType, valueLen, hf_string, headerType,
+           vals_openwave_field_names);
+}
+
+static void
+add_string_value_header_common (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen, int hf_string, guint8 headerType,
+    const value_string *vals)
 {
        if (valueType != VALUE_IS_TEXT_STRING)
        {
                proto_tree_add_text (tree, header_buff, 0, headerLen,
                    "Invalid %s string value",
-                   match_strval (headerType, vals_field_names));
+                   match_strval (headerType, vals));
        }
        else
        {
@@ -2749,6 +3458,24 @@ add_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
        }
 }
 
+static void
+add_quoted_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
+    int headerLen, tvbuff_t *value_buff, value_type_t valueType,
+    int valueLen, int hf_string, guint8 headerType)
+{
+       if (valueType != VALUE_IS_TEXT_STRING)
+       {
+               proto_tree_add_text (tree, header_buff, 0, headerLen,
+                   "Invalid %s quoted string value",
+                   match_strval (headerType, vals_field_names));
+       }
+       else
+       {
+               proto_tree_add_string (tree, hf_string, header_buff,
+                       0, headerLen, tvb_get_ptr (value_buff, 1, valueLen - 1));
+       }
+}
+
 /* Utility function to add a date value to the protocol tree */
 static void
 add_date_value_header (proto_tree *tree, tvbuff_t *header_buff,
@@ -2756,7 +3483,7 @@ add_date_value_header (proto_tree *tree, tvbuff_t *header_buff,
     int valueLen, int hf_time, guint8 headerType)
 {
        guint secs;
-       struct timeval timeValue;
+       nstime_t timeValue;
 
        /* Attempt to get the date value from the buffer */
        if (get_integer (value_buff, 0, valueLen, valueType, &secs) == 0)
@@ -2770,8 +3497,8 @@ add_date_value_header (proto_tree *tree, tvbuff_t *header_buff,
                 * there weren't WAP phones or Web servers back in
                 * late 1969/early 1970, they're unlikely to be used.
                 */
-               timeValue.tv_sec = secs;
-               timeValue.tv_usec = 0;
+               timeValue.secs = secs;
+               timeValue.nsecs = 0;
                proto_tree_add_time (tree, hf_time, header_buff, 0,
                        headerLen, &timeValue);
        }
@@ -2800,7 +3527,7 @@ add_parameter (proto_tree *tree, tvbuff_t *value_buff, int offset)
                /*
                 * Untyped-parameter.
                 */
-               add_untyped_parameter (tree, value_buff, startOffset, offset);
+               offset = add_untyped_parameter (tree, value_buff, startOffset, offset);
                return offset;
        }
 
@@ -2819,53 +3546,56 @@ add_parameter (proto_tree *tree, tvbuff_t *value_buff, int offset)
        switch (value) {
 
        case 0x01:      /* Charset */
-               add_parameter_charset (tree, value_buff, startOffset, offset);
+               offset = add_parameter_charset (tree, value_buff, startOffset, offset);
                break;
 
        case 0x03:      /* Type */
-               add_parameter_type (tree, value_buff, startOffset, offset);
+               offset = add_parameter_type (tree, value_buff, startOffset, offset);
                break;
 
        case 0x05:      /* Name */
-               add_parameter_text (tree, value_buff, startOffset, offset,
-                   hf_wsp_parameter_name, "Name");
+               offset = add_parameter_text (tree, value_buff, startOffset, offset,
+                                   hf_wsp_parameter_name, "Name");
                break;
 
        case 0x06:      /* Filename */
-               add_parameter_text (tree, value_buff, startOffset, offset,
-                   hf_wsp_parameter_filename, "Filename");
+               offset = add_parameter_text (tree, value_buff, startOffset, offset,
+                                   hf_wsp_parameter_filename, "Filename");
+               break;
+
+       case 0x09:      /* Type (special) */
+               offset = add_constrained_encoding(tree, value_buff, startOffset, offset);
                break;
 
        case 0x0A:      /* Start */
-               add_parameter_text (tree, value_buff, startOffset, offset,
-                   hf_wsp_parameter_start, "Start");
+               offset = add_parameter_text (tree, value_buff, startOffset, offset,
+                                   hf_wsp_parameter_start, "Start");
                break;
 
        case 0x0B:      /* Start-info */
-               add_parameter_text (tree, value_buff, startOffset, offset,
-                   hf_wsp_parameter_start_info, "Start-info");
+               offset = add_parameter_text (tree, value_buff, startOffset, offset,
+                                   hf_wsp_parameter_start_info, "Start-info");
                break;
 
        case 0x0C:      /* Comment */
-               add_parameter_text (tree, value_buff, startOffset, offset,
-                   hf_wsp_parameter_comment, "Comment");
+               offset = add_parameter_text (tree, value_buff, startOffset, offset,
+                                   hf_wsp_parameter_comment, "Comment");
                break;
 
        case 0x0D:      /* Domain */
-               add_parameter_text (tree, value_buff, startOffset, offset,
-                   hf_wsp_parameter_domain, "Domain");
+               offset = add_parameter_text (tree, value_buff, startOffset, offset,
+                                   hf_wsp_parameter_domain, "Domain");
                break;
 
        case 0x0F:      /* Path */
-               add_parameter_text (tree, value_buff, startOffset, offset,
-                   hf_wsp_parameter_path, "Path");
+               offset = add_parameter_text (tree, value_buff, startOffset, offset,
+                                   hf_wsp_parameter_path, "Path");
                break;
 
        case 0x00:      /* Q */
        case 0x02:      /* Level */
        case 0x07:      /* Differences */
        case 0x08:      /* Padding */
-       case 0x09:      /* Type (special) */
        case 0x0E:      /* Max-Age */
        case 0x10:      /* Secure */
        default:
@@ -2875,38 +3605,18 @@ add_parameter (proto_tree *tree, tvbuff_t *value_buff, int offset)
        return offset;
 }
 
-static void
+static int
 add_untyped_parameter (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
     int offset)
 {
-       int tokenOffset;
-       gint tokenLen;
        const guint8 *token;
        value_type_t valueType;
        int subvalueLen;
        int subvalueOffset;
        guint value;
-       int textvOffset;
-       gint stringLen;
-
-       tokenOffset = offset;
-       tokenLen = tvb_strnlen(value_buff, tokenOffset, -1);
-       if (tokenLen == -1) {
-               /*
-                * Make the length (not including the null byte at the
-                * end) the remaining reported length of the tvbuffer;
-                * this should cause us to throw the correct exception
-                * when we try to do a tvb_get_ptr starting at that
-                * offset with that length + 1, which is what we want
-                * (we ran past the end of the buffer trying
-                * to find the End-of-string).
-                */
-               tokenLen = tvb_reported_length_remaining (value_buff, tokenOffset);
-       }
-       tokenLen++;     /* include the terminating null byte */
-       token = tvb_get_ptr (value_buff, tokenOffset, tokenLen);
-       offset += tokenLen;
+       int vOffset = offset;
 
+       token = tvb_get_ptr (value_buff, startOffset, offset - startOffset);
        /*
         * Now an Untyped-value; either an Integer-value or a Text-value.
         */
@@ -2917,36 +3627,20 @@ add_untyped_parameter (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
                /*
                 * Text-value.
                 */
-               textvOffset = offset;
-               stringLen = tvb_strnlen (value_buff, textvOffset, -1);
-               if (stringLen == 0) {
+               if ((offset - vOffset) == 1) {
                        /*
-                        * No-value.
+                        * No-value.  (stringSize includes the terminating
+                        * null byte, so an empty string has a size of 1.)
                         */
                        proto_tree_add_text (tree, value_buff, startOffset,
                            offset - startOffset,
                            "%s", token);
-                       return;
-               }                       
-               if (stringLen == -1) {
-                       /*
-                        * Make the length (not including the null byte at the
-                        * end) the remaining reported length of the tvbuffer;
-                        * this should cause us to throw the correct exception
-                        * when we try to do a tvb_get_ptr starting at that
-                        * offset with that length + 1, which is what we want
-                        * (we ran past the end of the buffer trying
-                        * to find the End-of-string).
-                        */
-                       stringLen =
-                           tvb_reported_length_remaining (value_buff, textvOffset);
+                       return offset;
                }
-               stringLen++;    /* include the terminating null byte */
-               offset += stringLen;
                proto_tree_add_text (tree, value_buff, startOffset,
                    offset - startOffset,
                    "%s: %s", token,
-                   tvb_get_ptr (value_buff, textvOffset, stringLen));
+                   tvb_get_ptr (value_buff, vOffset, offset - vOffset));
        }
        else
        {
@@ -2967,9 +3661,10 @@ add_untyped_parameter (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
                            "%s: Invalid Integer-value", token);
                }
        }
+       return offset;
 }
 
-static void
+static int
 add_parameter_charset (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
     int offset)
 {
@@ -2988,7 +3683,7 @@ add_parameter_charset (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
                proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset,
                    value_buff, startOffset, offset - startOffset,
                    subvalueLen);       /* subvalueLen is the value */
-               return;
+               return offset;
        }
        if (valueType == VALUE_IS_TEXT_STRING)
        {
@@ -2997,7 +3692,7 @@ add_parameter_charset (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
                 */
                proto_tree_add_text (tree, value_buff, startOffset,
                    offset - startOffset, "Invalid Well-known charset");
-               return;
+               return offset;
        }
 
        /*
@@ -3010,7 +3705,7 @@ add_parameter_charset (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
                 */
                proto_tree_add_text (tree, value_buff, startOffset,
                    offset- startOffset, "*");
-               return;
+               return offset;
        }
 
        if (get_integer(value_buff, subvalueOffset, subvalueLen,
@@ -3022,9 +3717,49 @@ add_parameter_charset (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
                proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset,
                    value_buff, startOffset, offset - startOffset, value);
        }
+       return offset;
 }
 
-static void
+static int
+add_constrained_encoding (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
+    int offset)
+{
+       value_type_t valueType;
+       int subvalueLen;
+       int subvalueOffset;
+       guint value;
+
+       valueType = get_value_type_len (value_buff, offset,
+           &subvalueLen, &subvalueOffset, &offset);
+       if (valueType == VALUE_IN_LEN)
+       {
+               /*
+                * Integer-value, invalid
+                */
+               proto_tree_add_text (tree, value_buff, startOffset,
+                   offset - startOffset, "Invalid multipart type parameter");
+               return offset;
+       }
+       if (valueType == VALUE_IS_TEXT_STRING)
+       {
+               /*
+                * type-label.
+                */
+               proto_tree_add_string (tree, hf_wsp_parameter_upart_type,
+                   value_buff, startOffset, offset - startOffset,
+                   tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
+               return offset;
+       }
+       /*
+        * First byte had the 8th bit set.
+        */
+       get_integer(value_buff, subvalueOffset, subvalueLen, valueType, &value);
+       proto_tree_add_uint (tree, hf_wsp_parameter_upart_type_value,
+           value_buff, startOffset, offset - startOffset, value);
+       return offset;
+}
+
+static int
 add_parameter_type (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
     int offset)
 {
@@ -3043,9 +3778,10 @@ add_parameter_type (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
                proto_tree_add_uint (tree, hf_wsp_parameter_type, value_buff,
                    startOffset, offset - startOffset, value);
        }
+       return offset;
 }
 
-static void
+static int
 add_parameter_text (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
     int offset, int hf_string, const char *paramName)
 {
@@ -3059,9 +3795,11 @@ add_parameter_text (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
                proto_tree_add_text (tree, value_buff, startOffset,
                    offset - startOffset, "Invalid %s", paramName);
        } else {
-               proto_tree_add_item (tree, hf_string, value_buff,
-                   startOffset, offset - startOffset, bo_little_endian);
+               proto_tree_add_string (tree, hf_string, value_buff,
+                           startOffset, offset - startOffset,
+                           tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
        }
+       return offset;
 }
 
 static void
@@ -3076,8 +3814,8 @@ add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType,
        guint8 peek = 0;
        proto_item *ti;
        
-       /* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_length_remaining(tvb, offset),bo_little_endian); */
-       ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_reported_length(tvb),bo_little_endian);
+       /* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,-1,bo_little_endian); */
+       ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,-1,bo_little_endian);
 
        if (contentTypeStr == NULL && contentType == 0x12)
        {
@@ -3112,6 +3850,11 @@ add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType,
                        add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
                }
        }
+       else if ((contentType == 0x22) || (contentType == 0x23) || (contentType == 0x23) || (contentType == 0x24) ||
+                (contentType == 0x25) || (contentType == 0x26) || (contentType == 0x33))
+       {
+               add_multipart_data(ti, tvb);
+       }
 }
 
 static void
@@ -3154,6 +3897,57 @@ add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint v
        g_free (valueBuffer);
 }
 
+void
+add_multipart_data (proto_tree *tree, tvbuff_t *tvb)
+{
+       int              offset = 0;
+       guint            nextOffset;
+       guint            nEntries = 0;
+       guint            count;
+       guint            HeadersLen;
+       guint            DataLen;
+       guint            contentType = 0;
+       const char      *contentTypeStr;
+       tvbuff_t        *tmp_tvb;
+       int              partnr = 1;
+       int              part_start;
+
+       proto_item      *sub_tree = NULL,
+                       *ti;
+       proto_tree      *mpart_tree;
+
+       nEntries = tvb_get_guintvar (tvb, offset, &count);
+       offset += count;
+       if (nEntries)
+       {
+               sub_tree = proto_tree_add_text(tree, tvb, offset - count, 0,
+                                       "Multipart body");
+               proto_item_add_subtree(sub_tree, ett_mpartlist);
+       }
+       while (nEntries--)
+       {
+               part_start = offset;
+               HeadersLen = tvb_get_guintvar (tvb, offset, &count);
+               offset += count;
+               DataLen = tvb_get_guintvar (tvb, offset, &count);
+               offset += count;
+               ti = proto_tree_add_uint(sub_tree, hf_wsp_mpart, tvb, part_start,
+                                       HeadersLen + DataLen + (offset - part_start), partnr);
+               mpart_tree = proto_item_add_subtree(ti, ett_multiparts);
+               nextOffset = add_content_type (mpart_tree, tvb, offset, &contentType, &contentTypeStr);
+               HeadersLen -= (nextOffset - offset);
+               if (HeadersLen > 0)
+               {
+                       tmp_tvb = tvb_new_subset (tvb, nextOffset, HeadersLen, HeadersLen);
+                       add_headers (mpart_tree, tmp_tvb);
+               }
+               offset = nextOffset + HeadersLen;
+               proto_tree_add_item (mpart_tree, hf_wsp_multipart_data, tvb, offset, DataLen, bo_little_endian);
+               offset += DataLen;
+               partnr++;
+       }
+}
+
 static gint
 get_integer (tvbuff_t *tvb, guint offset, guint valueLength,
     value_type_t valueType, guint *value)
@@ -3374,6 +4168,20 @@ proto_register_wsp(void)
                                "Path", HFILL
                        }
                },
+               { &hf_wsp_parameter_upart_type,
+                       {       "Type",
+                               "wsp.content_type.parameter.upart.type",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Multipart type", HFILL
+                       }
+               },
+               { &hf_wsp_parameter_upart_type_value,
+                       {       "Type",
+                               "wsp.content_type.parameter.upart.type.int",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Multipart type (int value)", HFILL
+                       }
+               },
                { &hf_wsp_reply_data,
                        {       "Data",           
                                "wsp.reply.data",
@@ -3467,6 +4275,223 @@ proto_register_wsp(void)
                                "Age", HFILL
                        }
                },
+               { &hf_wsp_header_openwave_proxy_push_addr,
+                       {       "x-up-proxy-push-addr",
+                               "wsp.header.x-up-proxy-push-addr",
+                                FT_BYTES, BASE_HEX, NULL, 0x00,
+                               "The network address and port number that the handset can receive UPNOTIFY pushes on.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_push_accept,
+                       {       "x-up-proxy-push-accept",
+                               "wsp.header.x-up-proxy-push-accept",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "The content types that the handset can handle when sent via UPNOTIFY pushes.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_push_seq,
+                       {       "x-up-proxy-push-seq",
+                               "wsp.header.x-up-proxy-push-seq",
+                                FT_UINT16, BASE_DEC, NULL, 0x00,
+                               "Specifies the sequence number of the last UPNOTIFY push sent.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_notify,
+                       {       "x-up-proxy-notify",           
+                               "wsp.header.x-up-proxy-notify",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates to the handset that there are pending UPNOTIFY pushes waiting.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_operator_domain,
+                       {       "x-up-proxy-operator-domain",           
+                               "wsp.header.x-up-proxy-operator-domain",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Indicates the Trusted Provisioning Domain.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_home_page,
+                       {       "x-up-proxy-home-page",           
+                               "wsp.header.x-up-proxy-home-page",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Specifies the server-assigned home page URL.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_has_color,
+                       {       "x-up-devcap-has-color",           
+                               "wsp.header.x-up-devcap-has-color",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates if the handset supports colour.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_num_softkeys,
+                       {       "x-up-devcap-num-softkeys",
+                               "wsp.header.x-up-devcap-num-softkeys",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "The number of softkeys that can be displayed on the handset.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_softkey_size,
+                       {       "x-up-devcap-softkey-size",
+                               "wsp.header.x-up-devcap-softkey-size",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "The number of chars that can be displayed on a softkey label.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_screen_chars,
+                       {       "x-up-devcap-screen-chars",
+                               "wsp.header.x-up-devcap-screen-chars",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "The height and width of the handset's display in characters.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_screen_pixels,
+                       {       "x-up-devcap-screen-pixels",
+                               "wsp.header.x-up-devcap-screen-pixels",
+                                FT_UINT32, BASE_DEC, NULL, 0x00,
+                               "The height and width of the handset's display in pixels.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_em_size,
+                       {       "x-up-devcap-em-size",
+                               "wsp.header.x-up-devcap-em-size",
+                                FT_UINT32, BASE_DEC, NULL, 0x00,
+                               "The height and width of an uppercase M in pixels in a handset.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_screen_depth,
+                       {       "x-up-devcap-screen-depth",
+                               "wsp.header.x-up-devcap-screen-depth",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "The colour/gray depth of the display in bits.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_immed_alert,
+                       {       "x-up-devcap-immed-alert",
+                               "wsp.header.x-up-devcap-immed-alert",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates if the handset has support for immediate UPNOTIFY alerts.", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_net_ask,
+                       {       "x-up-proxy-net-ask",
+                               "wsp.header.x-up-proxy-net-ask",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates to browser if circuit switched call is allowed without user interaction", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_uplink_version,
+                       {       "x-up-proxy-uplink-version",
+                               "wsp.header.x-up-proxy-uplink-version",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Version of the MAG WAP gateway", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_tod,
+                       {       "x-up-proxy-tod",
+                               "wsp.header.x-up-proxy-tod",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Time of day", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_ba_enable,
+                       {       "x-up-proxy-ba-enable",
+                               "wsp.header.x-up-proxy-ba-enable",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates if the WAP gateway should cache basic authentication details on behalf of the handset", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_ba_realm,
+                       {       "x-up-proxy-ba-realm",
+                               "wsp.header.x-up-proxy-ba-realm",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Indicates the realm within which basic authentication credentials apply", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_redirect_enable,
+                       {       "x-up-proxy-redirect-enable",
+                               "wsp.header.x-up-proxy-redirect-enable",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates if the handset wants the WAP gateway to handle HTTP redirects on its behalf", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_request_uri,
+                       {       "x-up-proxy-request-uri",
+                               "wsp.header.x-up-proxy-request-uri",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Indicates to the handset that the previous request was redirected to the specified URI", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_redirect_status,
+                       {       "x-up-proxy-redirect-status",
+                               "wsp.header.x-up-proxy-redirect-status",
+                                FT_UINT32, BASE_DEC, NULL, 0x00,
+                               "Indicates the status of a redirect performed on behalf of a handset", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_trans_charset,
+                       {       "x-up-proxy-trans-charset",
+                               "wsp.header.x-up-proxy-trans-charset",
+                                FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
+                               "For POSTs indicates the charset encoding of a document", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_trans_charset_str,
+                       {       "x-up-proxy-trans-charset",
+                               "wsp.header.x-up-proxy-trans-charset.string",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "For POSTs indicates the charset encoding of a document", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_linger,
+                       {       "x-up-proxy-linger",
+                               "wsp.header.x-up-proxy-linger",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates the circuit linger time in seconds", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_client_id,
+                       {       "x-up-proxy-client-id",
+                               "wsp.header.x-up-proxy-client-id",
+                                FT_BYTES, BASE_DEC, NULL, 0x00,
+                               "The ClientId of the handset", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_enable_trust,
+                       {       "x-up-proxy-enable-trust",
+                               "wsp.header.x-up-proxy-enable-trust",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates whether to enable Trusted Provisioning Domain", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_trust_old,
+                       {       "x-up-proxy-trust-old",
+                               "wsp.header.x-up-proxy-trust-old",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates if the content being returned was received from within the Trusted Provisioning Domain", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_trust,
+                       {       "x-up-proxy-trust",
+                               "wsp.header.x-up-proxy-trust",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates if the content being returned was received from within the Trusted Provisioning Domain", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_proxy_bookmark,
+                       {       "x-up-proxy-bookmark",
+                               "wsp.header.x-up-proxy-bookmark",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Specifies the URL to use for server-side bookmarks", HFILL
+                       }
+               },
+               { &hf_wsp_header_openwave_devcap_gui,
+                       {       "x-up-devcap-gui",
+                               "wsp.header.x-up-devcap-gui",
+                                FT_UINT8, BASE_DEC, NULL, 0x00,
+                               "Indicates if the handset has a GUI", HFILL
+                       }
+               },
                { &hf_wsp_header_bearer_indication,
                        /*
                         * XXX - I'm assuming that the bearer indication is
@@ -3506,6 +4531,20 @@ proto_register_wsp(void)
                                "Cache-Control field name", HFILL
                        }
                },
+               { &hf_wsp_header_connection,
+                       {       "Connection",           
+                               "wsp.header.connection",
+                                FT_UINT8, BASE_HEX, VALS ( vals_connection ), 0x00,
+                               "Connection", HFILL
+                       }
+               },
+               { &hf_wsp_header_connection_str,
+                       {       "Connection",           
+                               "wsp.header.connection_str",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Connection", HFILL
+                       }
+               },
                { &hf_wsp_header_content_length,
                        {       "Content-Length",           
                                "wsp.header.content_length",
@@ -3610,6 +4649,20 @@ proto_register_wsp(void)
                                "Via", HFILL
                        }
                },
+               { &hf_wsp_header_wap_application_id,
+                       {       "X-Wap-Application-Id",           
+                               "wsp.header.wap_application_id",
+                                FT_UINT8, BASE_HEX, NULL, 0x00,
+                               "WAP application id", HFILL
+                       }
+               },
+               { &hf_wsp_header_wap_application_id_str,
+                       {       "X-Wap-Application-Id",           
+                               "wsp.header.wap_application_id.string",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "WAP application id", HFILL
+                       }
+               },
                { &hf_wsp_header_warning,
                        {       "Warning",
                                "wsp.header.warning",
@@ -3652,6 +4705,13 @@ proto_register_wsp(void)
                                "Application Header Value", HFILL
                        }
                },
+               { &hf_wsp_header_content_ID,
+                       {       "Content-ID",           
+                               "wsp.header.content-id",
+                                FT_STRING, BASE_NONE, NULL, 0x00,
+                               "Content-ID", HFILL
+                       }
+               },
                { &hf_wsp_header_x_wap_tod,
                        {       "X-WAP.TOD",           
                                "wsp.header.x_wap_tod",
@@ -3722,6 +4782,27 @@ proto_register_wsp(void)
                                "Post Data", HFILL
                        }
                },
+               { &hf_wsp_push_data,
+                       {       "Push Data",           
+                               "wsp.push.data",
+                                FT_NONE, BASE_NONE, NULL, 0x00,
+                               "Push Data", HFILL
+                       }
+               },
+               { &hf_wsp_multipart_data,
+                       {       "Data in this part",           
+                               "wsp.multipart.data",
+                                FT_NONE, BASE_NONE, NULL, 0x00,
+                               "The data of 1 MIME-multipart part.", HFILL
+                       }
+               },
+               { &hf_wsp_mpart,
+                       {       "Part",           
+                               "wsp.multipart",
+                                FT_UINT32, BASE_DEC, NULL, 0x00,
+                               "MIME part of multipart data.", HFILL
+                       }
+               },
                { &hf_wsp_redirect_flags,
                        {       "Flags",
                                "wsp.redirect_flags",
@@ -3821,6 +4902,8 @@ proto_register_wsp(void)
                &ett_content_type,
                &ett_redirect_flags,
                &ett_redirect_afl,
+               &ett_multiparts,
+               &ett_mpartlist
        };
 
 /* Register the protocol name and description */
@@ -3838,18 +4921,30 @@ proto_register_wsp(void)
 
        register_dissector("wsp-co", dissect_wsp_fromwap_co, proto_wsp);
        register_dissector("wsp-cl", dissect_wsp_fromwap_cl, proto_wsp);
+       wsp_dissector_table = register_dissector_table("wsp.content_type.type",
+           "WSP content type", FT_UINT8, BASE_HEX);
+       register_heur_dissector_list("wsp", &heur_subdissector_list);
+
+       wsp_fromudp_handle = create_dissector_handle(dissect_wsp_fromudp,
+           proto_wsp);
 };
 
 void
 proto_reg_handoff_wsp(void)
 {
        /*
-        * Get a handle for the WMLC dissector
+        * Get a handle for the WMLC dissector.
         */
        wmlc_handle = find_dissector("wmlc");   /* Coming soon :) */
 
+       /*
+        * And get a handle for the WTP-over-UDP dissector.
+        */
+       wtp_fromudp_handle = find_dissector("wtp-udp");
+
        /* Only connection-less WSP has no previous handler */
-       dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp_fromudp, proto_wsp);
+       dissector_add("udp.port", UDP_PORT_WSP, wsp_fromudp_handle);
+       dissector_add("udp.port", UDP_PORT_WSP_PUSH, wsp_fromudp_handle);
 
        /* This dissector is also called from the WTP and WTLS dissectors */
 }