From Tom Uijldert: comment out an unused function.
[obnox/wireshark/wip.git] / packet-wsp.c
1 /* packet-wsp.c
2  *
3  * Routines to dissect WSP component of WAP traffic.
4  * 
5  * $Id: packet-wsp.c,v 1.55 2002/04/02 20:16:19 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * WAP dissector based on original work by Ben Fowler
12  * Updated by Neil Hunter <neil.hunter@energis-squared.com>
13  * WTLS support by Alexandre P. Ferreira (Splice IP)
14  * Openwave header support by Dermot Bradley <dermot.bradley@openwave.com>
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  * 
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * 
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
40 #endif
41
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
44 #endif
45
46 #ifdef NEED_SNPRINTF_H
47 # ifdef HAVE_STDARG_H
48 #  include <stdarg.h>
49 # else
50 #  include <varargs.h>
51 # endif
52 # include "snprintf.h"
53 #endif
54
55 #include <string.h>
56 #include <glib.h>
57 #include <epan/packet.h>
58 #include <epan/ipv6-utils.h>
59 #include <epan/conversation.h>
60 #include "packet-wap.h"
61 #include "packet-wsp.h"
62
63 /* File scoped variables for the protocol and registered fields */
64 static int proto_wsp                                    = HF_EMPTY;
65
66 /* These fields used by fixed part of header */
67 static int hf_wsp_header_tid                            = HF_EMPTY;
68 static int hf_wsp_header_pdu_type                       = HF_EMPTY;
69 static int hf_wsp_version_major                         = HF_EMPTY;
70 static int hf_wsp_version_minor                         = HF_EMPTY;
71 static int hf_wsp_capability_length                     = HF_EMPTY;
72 static int hf_wsp_capabilities_section                  = HF_EMPTY;
73 static int hf_wsp_capabilities_client_SDU               = HF_EMPTY;
74 static int hf_wsp_capabilities_server_SDU               = HF_EMPTY;
75 static int hf_wsp_capabilities_protocol_opt             = HF_EMPTY;
76 static int hf_wsp_capabilities_method_MOR               = HF_EMPTY;
77 static int hf_wsp_capabilities_push_MOR                 = HF_EMPTY;
78 static int hf_wsp_capabilities_extended_methods         = HF_EMPTY;
79 static int hf_wsp_capabilities_header_code_pages        = HF_EMPTY;
80 static int hf_wsp_capabilities_aliases                  = HF_EMPTY;
81 static int hf_wsp_header_uri_len                        = HF_EMPTY;
82 static int hf_wsp_header_uri                            = HF_EMPTY;
83 static int hf_wsp_server_session_id                     = HF_EMPTY;
84 static int hf_wsp_header_status                         = HF_EMPTY;
85 static int hf_wsp_header_length                         = HF_EMPTY;
86 static int hf_wsp_headers_section                       = HF_EMPTY;
87 static int hf_wsp_header                                = HF_EMPTY;
88 static int hf_wsp_content_type                          = HF_EMPTY;
89 static int hf_wsp_content_type_str                      = HF_EMPTY;
90 static int hf_wsp_parameter_well_known_charset          = HF_EMPTY;
91 static int hf_wsp_parameter_type                        = HF_EMPTY;
92 static int hf_wsp_parameter_name                        = HF_EMPTY;
93 static int hf_wsp_parameter_filename                    = HF_EMPTY;
94 static int hf_wsp_parameter_start                       = HF_EMPTY;
95 static int hf_wsp_parameter_start_info                  = HF_EMPTY;
96 static int hf_wsp_parameter_comment                     = HF_EMPTY;
97 static int hf_wsp_parameter_domain                      = HF_EMPTY;
98 static int hf_wsp_parameter_path                        = HF_EMPTY;
99 static int hf_wsp_parameter_upart_type                  = HF_EMPTY;
100 static int hf_wsp_parameter_upart_type_value            = HF_EMPTY;
101 static int hf_wsp_reply_data                            = HF_EMPTY;
102 static int hf_wsp_post_data                             = HF_EMPTY;
103 static int hf_wsp_push_data                             = HF_EMPTY;
104 static int hf_wsp_multipart_data                        = HF_EMPTY;
105 static int hf_wsp_mpart                                 = HF_EMPTY;
106
107 static int hf_wsp_header_shift_code                     = HF_EMPTY;
108 static int hf_wsp_header_accept                         = HF_EMPTY;
109 static int hf_wsp_header_accept_str                     = HF_EMPTY;
110 static int hf_wsp_header_accept_application             = HF_EMPTY;
111 static int hf_wsp_header_accept_application_str         = HF_EMPTY;
112 static int hf_wsp_header_accept_charset                 = HF_EMPTY;
113 static int hf_wsp_header_accept_charset_str             = HF_EMPTY;
114 static int hf_wsp_header_accept_language                = HF_EMPTY;
115 static int hf_wsp_header_accept_language_str            = HF_EMPTY;
116 static int hf_wsp_header_accept_ranges                  = HF_EMPTY;
117 static int hf_wsp_header_accept_ranges_str              = HF_EMPTY;
118 static int hf_wsp_header_cache_control                  = HF_EMPTY;
119 static int hf_wsp_header_cache_control_str              = HF_EMPTY;
120 static int hf_wsp_header_cache_control_field_name       = HF_EMPTY;
121 static int hf_wsp_header_connection                     = HF_EMPTY;
122 static int hf_wsp_header_connection_str                 = HF_EMPTY;
123 static int hf_wsp_header_cache_control_field_name_str   = HF_EMPTY;
124 static int hf_wsp_header_content_length                 = HF_EMPTY;
125 static int hf_wsp_header_age                            = HF_EMPTY;
126 static int hf_wsp_header_bearer_indication              = HF_EMPTY;
127 static int hf_wsp_header_date                           = HF_EMPTY;
128 static int hf_wsp_header_etag                           = HF_EMPTY;
129 static int hf_wsp_header_expires                        = HF_EMPTY;
130 static int hf_wsp_header_last_modified                  = HF_EMPTY;
131 static int hf_wsp_header_location                       = HF_EMPTY;
132 static int hf_wsp_header_if_modified_since              = HF_EMPTY;
133 static int hf_wsp_header_profile                        = HF_EMPTY;
134 static int hf_wsp_header_pragma                         = HF_EMPTY;
135 static int hf_wsp_header_server                         = HF_EMPTY;
136 static int hf_wsp_header_user_agent                     = HF_EMPTY;
137 static int hf_wsp_header_warning                        = HF_EMPTY;
138 static int hf_wsp_header_warning_code                   = HF_EMPTY;
139 static int hf_wsp_header_warning_agent                  = HF_EMPTY;
140 static int hf_wsp_header_warning_text                   = HF_EMPTY;
141 static int hf_wsp_header_application_header             = HF_EMPTY;
142 static int hf_wsp_header_application_value              = HF_EMPTY;
143 static int hf_wsp_header_x_wap_tod                      = HF_EMPTY;
144 static int hf_wsp_header_content_ID                     = HF_EMPTY;
145 static int hf_wsp_header_transfer_encoding              = HF_EMPTY;
146 static int hf_wsp_header_transfer_encoding_str          = HF_EMPTY;
147 static int hf_wsp_header_via                            = HF_EMPTY;
148 static int hf_wsp_header_wap_application_id             = HF_EMPTY;
149 static int hf_wsp_header_wap_application_id_str         = HF_EMPTY;
150
151
152 /* Openwave-specific WSP headers */
153 static int hf_wsp_header_openwave_proxy_push_addr       = HF_EMPTY;
154 static int hf_wsp_header_openwave_proxy_push_accept     = HF_EMPTY;
155 static int hf_wsp_header_openwave_proxy_push_seq        = HF_EMPTY;
156 static int hf_wsp_header_openwave_proxy_notify          = HF_EMPTY;
157 static int hf_wsp_header_openwave_proxy_operator_domain = HF_EMPTY;
158 static int hf_wsp_header_openwave_proxy_home_page       = HF_EMPTY;
159 static int hf_wsp_header_openwave_devcap_has_color      = HF_EMPTY;
160 static int hf_wsp_header_openwave_devcap_num_softkeys   = HF_EMPTY;
161 static int hf_wsp_header_openwave_devcap_softkey_size   = HF_EMPTY;
162 static int hf_wsp_header_openwave_devcap_screen_chars   = HF_EMPTY;
163 static int hf_wsp_header_openwave_devcap_screen_pixels  = HF_EMPTY;
164 static int hf_wsp_header_openwave_devcap_em_size        = HF_EMPTY;
165 static int hf_wsp_header_openwave_devcap_screen_depth   = HF_EMPTY;
166 static int hf_wsp_header_openwave_devcap_immed_alert    = HF_EMPTY;
167 static int hf_wsp_header_openwave_proxy_net_ask         = HF_EMPTY;
168 static int hf_wsp_header_openwave_proxy_uplink_version  = HF_EMPTY;
169 static int hf_wsp_header_openwave_proxy_tod             = HF_EMPTY;
170 static int hf_wsp_header_openwave_proxy_ba_enable       = HF_EMPTY;
171 static int hf_wsp_header_openwave_proxy_ba_realm        = HF_EMPTY;
172 static int hf_wsp_header_openwave_proxy_redirect_enable = HF_EMPTY;
173 static int hf_wsp_header_openwave_proxy_request_uri     = HF_EMPTY;
174 static int hf_wsp_header_openwave_proxy_redirect_status = HF_EMPTY;
175 static int hf_wsp_header_openwave_proxy_trans_charset   = HF_EMPTY;
176 static int hf_wsp_header_openwave_proxy_trans_charset_str       = HF_EMPTY;
177 static int hf_wsp_header_openwave_proxy_linger          = HF_EMPTY;
178 static int hf_wsp_header_openwave_proxy_client_id       = HF_EMPTY;
179 static int hf_wsp_header_openwave_proxy_enable_trust    = HF_EMPTY;
180 static int hf_wsp_header_openwave_proxy_trust_old       = HF_EMPTY;
181 static int hf_wsp_header_openwave_proxy_trust           = HF_EMPTY;
182 static int hf_wsp_header_openwave_proxy_bookmark        = HF_EMPTY;
183 static int hf_wsp_header_openwave_devcap_gui            = HF_EMPTY;
184
185
186 static int hf_wsp_redirect_flags                        = HF_EMPTY;
187 static int hf_wsp_redirect_permanent                    = HF_EMPTY;
188 static int hf_wsp_redirect_reuse_security_session       = HF_EMPTY;
189 static int hf_wsp_redirect_afl                          = HF_EMPTY;
190 static int hf_wsp_redirect_afl_bearer_type_included     = HF_EMPTY;
191 static int hf_wsp_redirect_afl_port_number_included     = HF_EMPTY;
192 static int hf_wsp_redirect_afl_address_len              = HF_EMPTY;
193 static int hf_wsp_redirect_bearer_type                  = HF_EMPTY;
194 static int hf_wsp_redirect_port_num                     = HF_EMPTY;
195 static int hf_wsp_redirect_ipv4_addr                    = HF_EMPTY;
196 static int hf_wsp_redirect_ipv6_addr                    = HF_EMPTY;
197 static int hf_wsp_redirect_addr                         = HF_EMPTY;
198
199 /* Initialize the subtree pointers */
200 static gint ett_wsp                                     = ETT_EMPTY;
201 static gint ett_content_type_parameters                 = ETT_EMPTY;
202 static gint ett_header                                  = ETT_EMPTY;
203 static gint ett_headers                                 = ETT_EMPTY;
204 static gint ett_header_warning                          = ETT_EMPTY;
205 static gint ett_header_cache_control_parameters         = ETT_EMPTY;
206 static gint ett_header_cache_control_field_names        = ETT_EMPTY;
207 static gint ett_capabilities                            = ETT_EMPTY;
208 static gint ett_content_type                            = ETT_EMPTY;
209 static gint ett_redirect_flags                          = ETT_EMPTY;
210 static gint ett_redirect_afl                            = ETT_EMPTY;
211 static gint ett_multiparts                              = ETT_EMPTY;
212 static gint ett_mpartlist                               = ETT_EMPTY;
213
214 /* Handle for WSP-over-UDP dissector */
215 static dissector_handle_t wsp_fromudp_handle;
216
217 /* Handle for WTP-over-UDP dissector */
218 static dissector_handle_t wtp_fromudp_handle;
219
220 /* Handle for WMLC dissector */
221 static dissector_handle_t wmlc_handle;
222
223 static const value_string vals_pdu_type[] = {
224         { 0x00, "Reserved" },
225         { 0x01, "Connect" },
226         { 0x02, "ConnectReply" },
227         { 0x03, "Redirect" },
228         { 0x04, "Reply" },
229         { 0x05, "Disconnect" },
230         { 0x06, "Push" },
231         { 0x07, "ConfirmedPush" },
232         { 0x08, "Suspend" },
233         { 0x09, "Resume" },
234
235         /* 0x10 - 0x3F Unassigned */
236
237         { 0x40, "Get" },
238         { 0x41, "Options" },
239         { 0x42, "Head" },
240         { 0x43, "Delete" },
241         { 0x44, "Trace" },
242
243         /* 0x45 - 0x4F Unassigned (Get PDU) */
244         /* 0x50 - 0x5F Extended method (Get PDU) */
245
246         { 0x60, "Post" },
247         { 0x61, "Put" },
248
249         /* 0x62 - 0x6F Unassigned (Post PDU) */
250         /* 0x70 - 0x7F Extended method (Post PDU) */
251         /* 0x80 - 0xFF Reserved */
252
253         { 0x00, NULL }
254
255 };
256
257 static const value_string vals_status[] = {
258         /* 0x00 - 0x0F Reserved */
259
260         { 0x10, "Continue" },
261         { 0x11, "Switching Protocols" },
262
263         { 0x20, "OK" },
264         { 0x21, "Created" },
265         { 0x22, "Accepted" },
266         { 0x23, "Non-Authoritative Information" },
267         { 0x24, "No Content" },
268         { 0x25, "Reset Content" },
269         { 0x26, "Partial Content" },
270
271         { 0x30, "Multiple Choices" },
272         { 0x31, "Moved Permanently" },
273         { 0x32, "Moved Temporarily" },
274         { 0x33, "See Other" },
275         { 0x34, "Not Modified" },
276         { 0x35, "Use Proxy" },
277         { 0x37, "Temporary Redirect" },
278
279         { 0x40, "Bad Request" },
280         { 0x41, "Unauthorised" },
281         { 0x42, "Payment Required" },
282         { 0x43, "Forbidden" },
283         { 0x44, "Not Found" },
284         { 0x45, "Method Not Allowed" },
285         { 0x46, "Not Acceptable" },
286         { 0x47, "Proxy Authentication Required" },
287         { 0x48, "Request Timeout" },
288         { 0x49, "Conflict" },
289         { 0x4A, "Gone" },
290         { 0x4B, "Length Required" },
291         { 0x4C, "Precondition Failed" },
292         { 0x4D, "Request Entity Too Large" },
293         { 0x4E, "Request-URI Too Large" },
294         { 0x4F, "Unsupported Media Type" },
295         { 0x50, "Requested Range Not Satisfiable" },
296         { 0x51, "Expectation Failed" },
297
298         { 0x60, "Internal Server Error" },
299         { 0x61, "Not Implemented" },
300         { 0x62, "Bad Gateway" },
301         { 0x63, "Service Unavailable" },
302         { 0x64, "Gateway Timeout" },
303         { 0x65, "HTTP Version Not Supported" },
304         { 0x00, NULL }
305 };
306
307 /*
308  * Field names.
309  */
310 #define FN_ACCEPT               0x00
311 #define FN_ACCEPT_CHARSET_DEP   0x01    /* encoding version 1.1, deprecated */
312 #define FN_ACCEPT_ENCODING_DEP  0x02    /* encoding version 1.1, deprecated */
313 #define FN_ACCEPT_LANGUAGE      0x03
314 #define FN_ACCEPT_RANGES        0x04
315 #define FN_AGE                  0x05
316 #define FN_ALLOW                0x06
317 #define FN_AUTHORIZATION        0x07
318 #define FN_CACHE_CONTROL_DEP    0x08    /* encoding version 1.1, deprecated */
319 #define FN_CONNECTION           0x09
320 #define FN_CONTENT_BASE         0x0A
321 #define FN_CONTENT_ENCODING     0x0B
322 #define FN_CONTENT_LANGUAGE     0x0C
323 #define FN_CONTENT_LENGTH       0x0D
324 #define FN_CONTENT_LOCATION     0x0E
325 #define FN_CONTENT_MD5          0x0F
326 #define FN_CONTENT_RANGE_DEP    0x10    /* encoding version 1.1, deprecated */
327 #define FN_CONTENT_TYPE         0x11
328 #define FN_DATE                 0x12
329 #define FN_ETAG                 0x13
330 #define FN_EXPIRES              0x14
331 #define FN_FROM                 0x15
332 #define FN_HOST                 0x16
333 #define FN_IF_MODIFIED_SINCE    0x17
334 #define FN_IF_MATCH             0x18
335 #define FN_IF_NONE_MATCH        0x19
336 #define FN_IF_RANGE             0x1A
337 #define FN_IF_UNMODIFIED_SINCE  0x1B
338 #define FN_LOCATION             0x1C
339 #define FN_LAST_MODIFIED        0x1D
340 #define FN_MAX_FORWARDS         0x1E
341 #define FN_PRAGMA               0x1F
342 #define FN_PROXY_AUTHENTICATE   0x20
343 #define FN_PROXY_AUTHORIZATION  0x21
344 #define FN_PUBLIC               0x22
345 #define FN_RANGE                0x23
346 #define FN_REFERER              0x24
347 #define FN_RETRY_AFTER          0x25
348 #define FN_SERVER               0x26
349 #define FN_TRANSFER_ENCODING    0x27
350 #define FN_UPGRADE              0x28
351 #define FN_USER_AGENT           0x29
352 #define FN_VARY                 0x2A
353 #define FN_VIA                  0x2B
354 #define FN_WARNING              0x2C
355 #define FN_WWW_AUTHENTICATE     0x2D
356 #define FN_CONTENT_DISPOSITION  0x2E
357 #define FN_X_WAP_APPLICATION_ID 0x2F
358 #define FN_X_WAP_CONTENT_URI    0x30
359 #define FN_X_WAP_INITIATOR_URI  0x31
360 #define FN_ACCEPT_APPLICATION   0x32
361 #define FN_BEARER_INDICATION    0x33
362 #define FN_PUSH_FLAG            0x34
363 #define FN_PROFILE              0x35
364 #define FN_PROFILE_DIFF         0x36
365 #define FN_PROFILE_WARNING      0x37
366 #define FN_EXPECT               0x38
367 #define FN_TE                   0x39
368 #define FN_TRAILER              0x3A
369 #define FN_ACCEPT_CHARSET       0x3B    /* encoding version 1.3 */
370 #define FN_ACCEPT_ENCODING      0x3C    /* encoding version 1.3 */
371 #define FN_CACHE_CONTROL        0x3D    /* encoding version 1.3 */
372 #define FN_CONTENT_RANGE        0x3E    /* encoding version 1.3 */
373 #define FN_X_WAP_TOD            0x3F
374 #define FN_CONTENT_ID           0x40
375 #define FN_SET_COOKIE           0x41
376 #define FN_COOKIE               0x42
377 #define FN_ENCODING_VERSION     0x43
378 #define FN_PROFILE_WARNING14    0x44    /* encoding version 1.4 */
379 #define FN_CONTENT_DISPOSITION14        0x45    /* encoding version 1.4 */
380 #define FN_X_WAP_SECURITY       0x46
381 #define FN_CACHE_CONTROL14      0x47    /* encoding version 1.4 */
382
383
384 /*
385  * Openwave field names.
386  */
387 #define FN_OPENWAVE_PROXY_PUSH_ADDR             0x00
388 #define FN_OPENWAVE_PROXY_PUSH_ACCEPT           0x01
389 #define FN_OPENWAVE_PROXY_PUSH_SEQ              0x02
390 #define FN_OPENWAVE_PROXY_NOTIFY                0x03
391 #define FN_OPENWAVE_PROXY_OPERATOR_DOMAIN       0x04
392 #define FN_OPENWAVE_PROXY_HOME_PAGE             0x05
393 #define FN_OPENWAVE_DEVCAP_HAS_COLOR            0x06
394 #define FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS         0x07
395 #define FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE         0x08
396 #define FN_OPENWAVE_DEVCAP_SCREEN_CHARS         0x09
397 #define FN_OPENWAVE_DEVCAP_SCREEN_PIXELS        0x0A
398 #define FN_OPENWAVE_DEVCAP_EM_SIZE              0x0B
399 #define FN_OPENWAVE_DEVCAP_SCREEN_DEPTH         0x0C
400 #define FN_OPENWAVE_DEVCAP_IMMED_ALERT          0x0D
401 #define FN_OPENWAVE_PROXY_NET_ASK               0x0E
402 #define FN_OPENWAVE_PROXY_UPLINK_VERSION        0x0F
403 #define FN_OPENWAVE_PROXY_TOD                   0x10
404 #define FN_OPENWAVE_PROXY_BA_ENABLE             0x11
405 #define FN_OPENWAVE_PROXY_BA_REALM              0x12
406 #define FN_OPENWAVE_PROXY_REDIRECT_ENABLE       0x13
407 #define FN_OPENWAVE_PROXY_REQUEST_URI           0x14
408 #define FN_OPENWAVE_PROXY_REDIRECT_STATUS       0x15
409 #define FN_OPENWAVE_PROXY_TRANS_CHARSET         0x16
410 #define FN_OPENWAVE_PROXY_LINGER                0x17
411 #define FN_OPENWAVE_PROXY_CLIENT_ID             0x18
412 #define FN_OPENWAVE_PROXY_ENABLE_TRUST          0x19
413 #define FN_OPENWAVE_PROXY_TRUST_OLD             0x1A
414 #define FN_OPENWAVE_PROXY_TRUST                 0x20
415 #define FN_OPENWAVE_PROXY_BOOKMARK              0x21
416 #define FN_OPENWAVE_DEVCAP_GUI                  0x22
417
418 static const value_string vals_openwave_field_names[] = {
419         { FN_OPENWAVE_PROXY_PUSH_ADDR,         "x-up-proxy-push-addr" },
420         { FN_OPENWAVE_PROXY_PUSH_ACCEPT,       "x-up-proxy-push-accept" },
421         { FN_OPENWAVE_PROXY_PUSH_SEQ,          "x-up-proxy-seq" },
422         { FN_OPENWAVE_PROXY_NOTIFY,            "x-up-proxy-notify" },
423         { FN_OPENWAVE_PROXY_OPERATOR_DOMAIN,   "x-up-proxy-operator-domain" },
424         { FN_OPENWAVE_PROXY_HOME_PAGE,         "x-up-proxy-home-page" },
425         { FN_OPENWAVE_DEVCAP_HAS_COLOR,        "x-up-devcap-has-color" },
426         { FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS,     "x-up-devcap-num-softkeys" },
427         { FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE,     "x-up-devcap-softkey-size" },
428         { FN_OPENWAVE_DEVCAP_SCREEN_CHARS,     "x-up-devcap-screen-chars" },
429         { FN_OPENWAVE_DEVCAP_SCREEN_PIXELS,    "x-up-devcap-screen-pixels" },
430         { FN_OPENWAVE_DEVCAP_EM_SIZE,          "x-up-devcap-em-size" },
431         { FN_OPENWAVE_DEVCAP_SCREEN_DEPTH,     "x-up-devcap-screen-depth" },
432         { FN_OPENWAVE_DEVCAP_IMMED_ALERT,      "x-up-devcap-immed-alert" },
433         { FN_OPENWAVE_PROXY_NET_ASK,           "x-up-proxy-net-ask" },
434         { FN_OPENWAVE_PROXY_UPLINK_VERSION,    "x-up-proxy-uplink-version" },
435         { FN_OPENWAVE_PROXY_TOD,               "x-up-proxy-tod" },
436         { FN_OPENWAVE_PROXY_BA_ENABLE,         "x-up-proxy-ba-enable" },
437         { FN_OPENWAVE_PROXY_BA_REALM,          "x-up-proxy-ba-realm" },
438         { FN_OPENWAVE_PROXY_REDIRECT_ENABLE,   "x-up-proxy-redirect-enable" },
439         { FN_OPENWAVE_PROXY_REQUEST_URI,       "x-up-proxy-request-uri" },
440         { FN_OPENWAVE_PROXY_REDIRECT_STATUS,   "x-up-proxy-redirect-status" },
441         { FN_OPENWAVE_PROXY_TRANS_CHARSET,     "x-up-proxy-trans-charset" },
442         { FN_OPENWAVE_PROXY_LINGER,            "x-up-proxy-linger" },
443         { FN_OPENWAVE_PROXY_CLIENT_ID,         "x-up-proxy-client-id" },
444         { FN_OPENWAVE_PROXY_ENABLE_TRUST,      "x-up-proxy-enable-trust" },
445         { FN_OPENWAVE_PROXY_TRUST_OLD,         "x-up-proxy-trust-old" },
446         { FN_OPENWAVE_PROXY_TRUST,             "x-up-proxy-trust" },
447         { FN_OPENWAVE_PROXY_BOOKMARK,          "x-up-proxy-bookmark" },
448         { FN_OPENWAVE_DEVCAP_GUI,              "x-up-devcap-gui" },
449         { 0,                                   NULL }
450 };      
451
452
453 static const value_string vals_field_names[] = {
454         { FN_ACCEPT,               "Accept" },
455         { FN_ACCEPT_CHARSET_DEP,   "Accept-Charset (encoding 1.1)" },
456         { FN_ACCEPT_ENCODING_DEP,  "Accept-Encoding (encoding 1.1)" },
457         { FN_ACCEPT_LANGUAGE,      "Accept-Language" },
458         { FN_ACCEPT_RANGES,        "Accept-Ranges" },
459         { FN_AGE,                  "Age" },
460         { FN_ALLOW,                "Allow" },
461         { FN_AUTHORIZATION,        "Authorization" },
462         { FN_CACHE_CONTROL_DEP,    "Cache-Control (encoding 1.1)" },
463         { FN_CONNECTION,           "Connection" },
464         { FN_CONTENT_BASE,         "Content-Base" },
465         { FN_CONTENT_ENCODING,     "Content-Encoding" },
466         { FN_CONTENT_LANGUAGE,     "Content-Language" },
467         { FN_CONTENT_LENGTH,       "Content-Length" },
468         { FN_CONTENT_LOCATION,     "Content-Location" },
469         { FN_CONTENT_MD5,          "Content-MD5" },
470         { FN_CONTENT_RANGE_DEP,    "Content-Range (encoding 1.1)" },
471         { FN_CONTENT_TYPE,         "Content-Type" },
472         { FN_DATE,                 "Date" },
473         { FN_ETAG,                 "Etag" },
474         { FN_EXPIRES,              "Expires" },
475         { FN_FROM,                 "From" },
476         { FN_HOST,                 "Host" },
477         { FN_IF_MODIFIED_SINCE,    "If-Modified-Since" },
478         { FN_IF_MATCH,             "If-Match" },
479         { FN_IF_NONE_MATCH,        "If-None-Match" },
480         { FN_IF_RANGE,             "If-Range" },
481         { FN_IF_UNMODIFIED_SINCE,  "If-Unmodified-Since" },
482         { FN_LOCATION,             "Location" },
483         { FN_LAST_MODIFIED,        "Last-Modified" },
484         { FN_MAX_FORWARDS,         "Max-Forwards" },
485         { FN_PRAGMA,               "Pragma" },
486         { FN_PROXY_AUTHENTICATE,   "Proxy-Authenticate" },
487         { FN_PROXY_AUTHORIZATION,  "Proxy-Authorization" },
488         { FN_PUBLIC,               "Public" },
489         { FN_RANGE,                "Range" },
490         { FN_REFERER,              "Referer" },
491         { FN_RETRY_AFTER,          "Retry-After" },
492         { FN_SERVER,               "Server" },
493         { FN_TRANSFER_ENCODING,    "Transfer-Encoding" },
494         { FN_UPGRADE,              "Upgrade" },
495         { FN_USER_AGENT,           "User-Agent" },
496         { FN_VARY,                 "Vary" },
497         { FN_VIA,                  "Via" },
498         { FN_WARNING,              "Warning" },
499         { FN_WWW_AUTHENTICATE,     "WWW-Authenticate" },
500         { FN_CONTENT_DISPOSITION,  "Content-Disposition" },
501         { FN_X_WAP_APPLICATION_ID, "X-Wap-Application-ID" },
502         { FN_X_WAP_CONTENT_URI,    "X-Wap-Content-URI" },
503         { FN_X_WAP_INITIATOR_URI,  "X-Wap-Initiator-URI" },
504         { FN_ACCEPT_APPLICATION,   "Accept-Application" },
505         { FN_BEARER_INDICATION,    "Bearer-Indication" },
506         { FN_PUSH_FLAG,            "Push-Flag" },
507         { FN_PROFILE,              "Profile" },
508         { FN_PROFILE_DIFF,         "Profile-Diff" },
509         { FN_PROFILE_WARNING,      "Profile-Warning" },
510         { FN_EXPECT,               "Expect" },
511         { FN_TE,                   "TE" },
512         { FN_TRAILER,              "Trailer" },
513         { FN_ACCEPT_CHARSET,       "Accept-Charset" },
514         { FN_ACCEPT_ENCODING,      "Accept-Encoding" },
515         { FN_CACHE_CONTROL,        "Cache-Control" },
516         { FN_CONTENT_RANGE,        "Content-Range" },
517         { FN_X_WAP_TOD,            "X-Wap-Tod" },
518         { FN_CONTENT_ID,           "Content-ID" },
519         { FN_SET_COOKIE,           "Set-Cookie" },
520         { FN_COOKIE,               "Cookie" },
521         { FN_ENCODING_VERSION,     "Encoding-Version" },
522         { FN_PROFILE_WARNING14,    "Profile-Warning (encoding 1.4)" },
523         { FN_CONTENT_DISPOSITION14,"Content-Disposition (encoding 1.4)" },
524         { FN_X_WAP_SECURITY,       "X-WAP-Security" },
525         { FN_CACHE_CONTROL14,      "Cache-Control (encoding 1.4)" },
526         { 0,                       NULL }
527 };      
528
529 /*
530  * Bearer types (from the WDP specification).
531  */
532 #define BT_IPv4                 0x00
533 #define BT_IPv6                 0x01
534 #define BT_GSM_USSD             0x02
535 #define BT_GSM_SMS              0x03
536 #define BT_ANSI_136_GUTS        0x04
537 #define BT_IS_95_SMS            0x05
538 #define BT_IS_95_CSD            0x06
539 #define BT_IS_95_PACKET_DATA    0x07
540 #define BT_ANSI_136_CSD         0x08
541 #define BT_ANSI_136_PACKET_DATA 0x09
542 #define BT_GSM_CSD              0x0A
543 #define BT_GSM_GPRS             0x0B
544 #define BT_GSM_USSD_IPv4        0x0C
545 #define BT_AMPS_CDPD            0x0D
546 #define BT_PDC_CSD              0x0E
547 #define BT_PDC_PACKET_DATA      0x0F
548 #define BT_IDEN_SMS             0x10
549 #define BT_IDEN_CSD             0x11
550 #define BT_IDEN_PACKET_DATA     0x12
551 #define BT_PAGING_FLEX          0x13
552 #define BT_PHS_SMS              0x14
553 #define BT_PHS_CSD              0x15
554 #define BT_GSM_USSD_GSM_SC      0x16
555 #define BT_TETRA_SDS_ITSI       0x17
556 #define BT_TETRA_SDS_MSISDN     0x18
557 #define BT_TETRA_PACKET_DATA    0x19
558 #define BT_PAGING_REFLEX        0x1A
559 #define BT_GSM_USSD_MSISDN      0x1B
560 #define BT_MOBITEX_MPAK         0x1C
561 #define BT_ANSI_136_GHOST       0x1D
562
563 static const value_string vals_bearer_types[] = {
564         { BT_IPv4,                 "IPv4" },
565         { BT_IPv6,                 "IPv6" },
566         { BT_GSM_USSD,             "GSM USSD" },
567         { BT_GSM_SMS,              "GSM SMS" },
568         { BT_ANSI_136_GUTS,        "ANSI-136 GUTS/R-Data" },
569         { BT_IS_95_SMS,            "IS-95 CDMA SMS" },
570         { BT_IS_95_CSD,            "IS-95 CDMA CSD" },
571         { BT_IS_95_PACKET_DATA,    "IS-95 CDMA Packet data" },
572         { BT_ANSI_136_CSD,         "ANSI-136 CSD" },
573         { BT_ANSI_136_PACKET_DATA, "ANSI-136 Packet data" },
574         { BT_GSM_CSD,              "GSM CSD" },
575         { BT_GSM_GPRS,             "GSM GPRS" },
576         { BT_GSM_USSD_IPv4,        "GSM USSD (IPv4 addresses)" },
577         { BT_AMPS_CDPD,            "AMPS CDPD" },
578         { BT_PDC_CSD,              "PDC CSD" },
579         { BT_PDC_PACKET_DATA,      "PDC Packet data" },
580         { BT_IDEN_SMS,             "IDEN SMS" },
581         { BT_IDEN_CSD,             "IDEN CSD" },
582         { BT_IDEN_PACKET_DATA,     "IDEN Packet data" },
583         { BT_PAGING_FLEX,          "Paging network FLEX(TM)" },
584         { BT_PHS_SMS,              "PHS SMS" },
585         { BT_PHS_CSD,              "PHS CSD" },
586         { BT_GSM_USSD_GSM_SC,      "GSM USSD (GSM Service Code addresses)" },
587         { BT_TETRA_SDS_ITSI,       "TETRA SDS (ITSI addresses)" },
588         { BT_TETRA_SDS_MSISDN,     "TETRA SDS (MSISDN addresses)" },
589         { BT_TETRA_PACKET_DATA,    "TETRA Packet data" },
590         { BT_PAGING_REFLEX,        "Paging network ReFLEX(TM)" },
591         { BT_GSM_USSD_MSISDN,      "GSM USSD (MSISDN addresses)" },
592         { BT_MOBITEX_MPAK,         "Mobitex MPAK" },
593         { BT_ANSI_136_GHOST,       "ANSI-136 GHOST/R-Data" },
594         { 0,                       NULL }
595 };
596
597 static const value_string vals_content_types[] = {
598         { 0x00, "*/*" },
599         { 0x01, "text/*" },
600         { 0x02, "text/html" },
601         { 0x03, "text/plain" },
602         { 0x04, "text/x-hdml" },
603         { 0x05, "text/x-ttml" },
604         { 0x06, "text/x-vCalendar" },
605         { 0x07, "text/x-vCard" },
606         { 0x08, "text/vnd.wap.wml" },
607         { 0x09, "text/vnd.wap.wmlscript" },
608         { 0x0A, "text/vnd.wap.channel" },
609         { 0x0B, "Multipart/*" },
610         { 0x0C, "Multipart/mixed" },
611         { 0x0D, "Multipart/form-data" },
612         { 0x0E, "Multipart/byteranges" },
613         { 0x0F, "Multipart/alternative" },
614         { 0x10, "application/*" },
615         { 0x11, "application/java-vm" },
616         { 0x12, "application/x-www-form-urlencoded" },
617         { 0x13, "application/x-hdmlc" },
618         { 0x14, "application/vnd.wap.wmlc" },
619         { 0x15, "application/vnd.wap.wmlscriptc" },
620         { 0x16, "application/vnd.wap.channelc" },
621         { 0x17, "application/vnd.wap.uaprof" },
622         { 0x18, "application/vnd.wap.wtls-ca-certificate" },
623         { 0x19, "application/vnd.wap.wtls-user-certificate" },
624         { 0x1A, "application/x-x509-ca-cert" },
625         { 0x1B, "application/x-x509-user-cert" },
626         { 0x1C, "image/*" },
627         { 0x1D, "image/gif" },
628         { 0x1E, "image/jpeg" },
629         { 0x1F, "image/tiff" },
630         { 0x20, "image/png" },
631         { 0x21, "image/vnd.wap.wbmp" },
632         { 0x22, "application/vnd.wap.multipart.*" },
633         { 0x23, "application/vnd.wap.multipart.mixed" },
634         { 0x24, "application/vnd.wap.multipart.form-data" },
635         { 0x25, "application/vnd.wap.multipart.byteranges" },
636         { 0x26, "application/vnd.wap.multipart.alternative" },
637         { 0x27, "application/xml" },
638         { 0x28, "text/xml" },
639         { 0x29, "application/vnd.wap.wbxml" },
640         { 0x2A, "application/x-x968-cross-cert" },
641         { 0x2B, "application/x-x968-ca-cert" },
642         { 0x2C, "application/x-x968-user-cert" },
643         { 0x2D, "text/vnd.wap.si" },
644         { 0x2E, "application/vnd.wap.sic" },
645         { 0x2F, "text/vnd.wap.sl" },
646         { 0x30, "application/vnd.wap.slc" },
647         { 0x31, "text/vnd.wap.co" },
648         { 0x32, "application/vnd.wap.coc" },
649         { 0x33, "application/vnd.wap.multipart.related" },
650         { 0x34, "application/vnd.wap.sia" },
651         { 0x35, "text/vnd.wap.connectivity-xml" },
652         { 0x36, "application/vnd.wap.connectivity-wbxml" },
653         { 0x37, "application/pkcs7-mime" },
654         { 0x38, "application/vnd.wap.hashed-certificate" },
655         { 0x39, "application/vnd.wap.signed-certificate" },
656         { 0x3A, "application/vnd.wap.cert-response" },
657         { 0x3B, "application/xhtml+xml" },
658         { 0x3C, "application/wml+xml" },
659         { 0x3D, "text/css" },
660         { 0x3E, "application/vnd.wap.mms-message" },
661         { 0x3F, "application/vnd.wap.rollover-certificate" },
662         { 0x201, "application/vnd.uplanet.cachop-wbxml" },
663         { 0x202, "application/vnd.uplanet.signal" },
664         { 0x203, "application/vnd.uplanet.alert-wbxml" },
665         { 0x204, "application/vnd.uplanet.list-wbxml" },
666         { 0x205, "application/vnd.uplanet.listcmd-wbxml" },
667         { 0x206, "application/vnd.uplanet.channel-wbxml" },
668         { 0x207, "application/vnd.uplanet.provisioning-status-uri" },
669         { 0x208, "x-wap.multipart/vnd.uplanet.header-set" },
670         { 0x209, "application/vnd.uplanet.bearer-choice-wbxml" },
671         { 0x20A, "application/vnd.phonecom.mmc-wbxml" },
672         { 0x20B, "application/vnd.nokia.syncset+wbxml" },
673         { 0x00, NULL }
674 };
675
676 static const value_string vals_languages[] = {
677         { 0x01, "Afar (aa)" },
678         { 0x02, "Abkhazian (ab)" },
679         { 0x03, "Afrikaans (af)" },
680         { 0x04, "Amharic (am)" },
681         { 0x05, "Arabic (ar)" },
682         { 0x06, "Assamese (as)" },
683         { 0x07, "Aymara (ay)" },
684         { 0x08, "Azerbaijani (az)" },
685         { 0x09, "Bashkir (ba)" },
686         { 0x0A, "Byelorussian (be)" },
687         { 0x0B, "Bulgarian (bg)" },
688         { 0x0C, "Bihari (bh)" },
689         { 0x0D, "Bislama (bi)" },
690         { 0x0E, "Bengali; Bangla (bn)" },
691         { 0x0F, "Tibetan (bo)" },
692         { 0x10, "Breton (br)" },
693         { 0x11, "Catalan (ca)" },
694         { 0x12, "Corsican (co)" },
695         { 0x13, "Czech (cs)" },
696         { 0x14, "Welsh (cy)" },
697         { 0x15, "Danish (da)" },
698         { 0x16, "German (de)" },
699         { 0x17, "Bhutani (dz)" },
700         { 0x18, "Greek (el)" },
701         { 0x19, "English (en)" },
702         { 0x1A, "Esperanto (eo)" },
703         { 0x1B, "Spanish (es)" },
704         { 0x1C, "Estonian (et)" },
705         { 0x1D, "Basque (eu)" },
706         { 0x1E, "Persian (fa)" },
707         { 0x1F, "Finnish (fi)" },
708         { 0x20, "Fiji (fj)" },
709         { 0x21, "Urdu (ur)" },
710         { 0x22, "French (fr)" },
711         { 0x23, "Uzbek (uz)" },
712         { 0x24, "Irish (ga)" },
713         { 0x25, "Scots Gaelic (gd)" },
714         { 0x26, "Galician (gl)" },
715         { 0x27, "Guarani (gn)" },
716         { 0x28, "Gujarati (gu)" },
717         { 0x29, "Hausa (ha)" },
718         { 0x2A, "Hebrew (formerly iw) (he)" },
719         { 0x2B, "Hindi (hi)" },
720         { 0x2C, "Croatian (hr)" },
721         { 0x2D, "Hungarian (hu)" },
722         { 0x2E, "Armenian (hy)" },
723         { 0x2F, "Vietnamese (vi)" },
724         { 0x30, "Indonesian (formerly in) (id)" },
725         { 0x31, "Wolof (wo)" },
726         { 0x32, "Xhosa (xh)" },
727         { 0x33, "Icelandic (is)" },
728         { 0x34, "Italian (it)" },
729         { 0x35, "Yoruba (yo)" },
730         { 0x36, "Japanese (ja)" },
731         { 0x37, "Javanese (jw)" },
732         { 0x38, "Georgian (ka)" },
733         { 0x39, "Kazakh (kk)" },
734         { 0x3A, "Zhuang (za)" },
735         { 0x3B, "Cambodian (km)" },
736         { 0x3C, "Kannada (kn)" },
737         { 0x3D, "Korean (ko)" },
738         { 0x3E, "Kashmiri (ks)" },
739         { 0x3F, "Kurdish (ku)" },
740         { 0x40, "Kirghiz (ky)" },
741         { 0x41, "Chinese (zh)" },
742         { 0x42, "Lingala (ln)" },
743         { 0x43, "Laothian (lo)" },
744         { 0x44, "Lithuanian (lt)" },
745         { 0x45, "Latvian, Lettish (lv)" },
746         { 0x46, "Malagasy (mg)" },
747         { 0x47, "Maori (mi)" },
748         { 0x48, "Macedonian (mk)" },
749         { 0x49, "Malayalam (ml)" },
750         { 0x4A, "Mongolian (mn)" },
751         { 0x4B, "Moldavian (mo)" },
752         { 0x4C, "Marathi (mr)" },
753         { 0x4D, "Malay (ms)" },
754         { 0x4E, "Maltese (mt)" },
755         { 0x4F, "Burmese (my)" },
756         { 0x50, "Ukrainian (uk)" },
757         { 0x51, "Nepali (ne)" },
758         { 0x52, "Dutch (nl)" },
759         { 0x53, "Norwegian (no)" },
760         { 0x54, "Occitan (oc)" },
761         { 0x55, "(Afan) Oromo (om)" },
762         { 0x56, "Oriya (or)" },
763         { 0x57, "Punjabi (pa)" },
764         { 0x58, "Polish (po)" },
765         { 0x59, "Pashto, Pushto (ps)" },
766         { 0x5A, "Portuguese (pt)" },
767         { 0x5B, "Quechua (qu)" },
768         { 0x5C, "Zulu (zu)" },
769         { 0x5D, "Kirundi (rn)" },
770         { 0x5E, "Romanian (ro)" },
771         { 0x5F, "Russian (ru)" },
772         { 0x60, "Kinyarwanda (rw)" },
773         { 0x61, "Sanskrit (sa)" },
774         { 0x62, "Sindhi (sd)" },
775         { 0x63, "Sangho (sg)" },
776         { 0x64, "Serbo-Croatian (sh)" },
777         { 0x65, "Sinhalese (si)" },
778         { 0x66, "Slovak (sk)" },
779         { 0x67, "Slovenian (sl)" },
780         { 0x68, "Samoan (sm)" },
781         { 0x69, "Shona (sn)" },
782         { 0x6A, "Somali (so)" },
783         { 0x6B, "Albanian (sq)" },
784         { 0x6C, "Serbian (sr)" },
785         { 0x6D, "Siswati (ss)" },
786         { 0x6E, "Sesotho (st)" },
787         { 0x6F, "Sundanese (su)" },
788         { 0x70, "Swedish (sv)" },
789         { 0x71, "Swahili (sw)" },
790         { 0x72, "Tamil (ta)" },
791         { 0x73, "Telugu (te)" },
792         { 0x74, "Tajik (tg)" },
793         { 0x75, "Thai (th)" },
794         { 0x76, "Tigrinya (ti)" },
795         { 0x77, "Turkmen (tk)" },
796         { 0x78, "Tagalog (tl)" },
797         { 0x79, "Setswana (tn)" },
798         { 0x7A, "Tonga (to)" },
799         { 0x7B, "Turkish (tr)" },
800         { 0x7C, "Tsonga (ts)" },
801         { 0x7D, "Tatar (tt)" },
802         { 0x7E, "Twi (tw)" },
803         { 0x7F, "Uighur (ug)" },
804         { 0x81, "Nauru (na)" },
805         { 0x82, "Faeroese (fo)" },
806         { 0x83, "Frisian (fy)" },
807         { 0x84, "Interlingua (ia)" },
808         { 0x85, "Volapuk (vo)" },
809         { 0x86, "Interlingue (ie)" },
810         { 0x87, "Inupiak (ik)" },
811         { 0x88, "Yiddish (formerly ji) (yi)" },
812         { 0x89, "Inuktitut (iu)" },
813         { 0x8A, "Greenlandic (kl)" },
814         { 0x8B, "Latin (la)" },
815         { 0x8C, "Rhaeto-Romance (rm)" },
816         { 0x00, NULL }
817 };
818
819 static const value_string vals_accept_ranges[] = {
820         { 0x00, "None" },
821         { 0x01, "Bytes" },
822         { 0x00, NULL }
823 };
824
825 #define NO_CACHE                0x00
826 #define NO_STORE                0x01
827 #define MAX_AGE                 0x02
828 #define MAX_STALE               0x03
829 #define MIN_FRESH               0x04
830 #define ONLY_IF_CACHED          0x05
831 #define PUBLIC                  0x06
832 #define PRIVATE                 0x07
833 #define NO_TRANSFORM            0x08
834 #define MUST_REVALIDATE         0x09
835 #define PROXY_REVALIDATE        0x0A
836 #define S_MAXAGE                0x0B
837
838 static const value_string vals_cache_control[] = {
839         { NO_CACHE,         "No-cache" },
840         { NO_STORE,         "No-store" },
841         { MAX_AGE,          "Max-age" },
842         { MAX_STALE,        "Max-stale" },
843         { MIN_FRESH,        "Min-fresh" },
844         { ONLY_IF_CACHED,   "Only-if-cached" },
845         { PUBLIC,           "Public" },
846         { PRIVATE,          "Private" },
847         { NO_TRANSFORM,     "No-transform" },
848         { MUST_REVALIDATE,  "Must-revalidate" },
849         { PROXY_REVALIDATE, "Proxy-revalidate" },
850         { S_MAXAGE,         "S-max-age" },
851         { 0x00,             NULL }
852 };
853
854 static const value_string vals_connection[] = {
855         { 0x00, "Close" },
856         { 0x00, NULL }
857 };
858
859 static const value_string vals_transfer_encoding[] = {
860         { 0x00, "Chunked" },
861         { 0x00, NULL }
862 };
863
864 /*
865  * Redirect flags.
866  */
867 #define PERMANENT_REDIRECT      0x80
868 #define REUSE_SECURITY_SESSION  0x40
869
870 /*
871  * Redirect address flags and length.
872  */
873 #define BEARER_TYPE_INCLUDED    0x80
874 #define PORT_NUMBER_INCLUDED    0x40
875 #define ADDRESS_LEN             0x3f
876
877 static const true_false_string yes_no_truth = { 
878         "Yes" ,
879         "No"
880 };
881
882 /*
883  * Windows appears to define DELETE.
884  */
885 #ifdef DELETE
886 #undef DELETE
887 #endif
888
889 enum {
890         RESERVED                = 0x00,
891         CONNECT                 = 0x01,
892         CONNECTREPLY            = 0x02,
893         REDIRECT                = 0x03,                 /* No sample data */
894         REPLY                   = 0x04,
895         DISCONNECT              = 0x05,
896         PUSH                    = 0x06,                 /* No sample data */
897         CONFIRMEDPUSH           = 0x07,                 /* No sample data */
898         SUSPEND                 = 0x08,                 /* No sample data */
899         RESUME                  = 0x09,                 /* No sample data */
900
901         GET                     = 0x40,
902         OPTIONS                 = 0x41,                 /* No sample data */
903         HEAD                    = 0x42,                 /* No sample data */
904         DELETE                  = 0x43,                 /* No sample data */
905         TRACE                   = 0x44,                 /* No sample data */
906
907         POST                    = 0x60,
908         PUT                     = 0x61,                 /* No sample data */
909 };
910
911 typedef enum {
912         VALUE_LEN_SUPPLIED,
913         VALUE_IS_TEXT_STRING,
914         VALUE_IN_LEN,
915 } value_type_t;
916
917 static dissector_table_t wsp_dissector_table;
918 static heur_dissector_list_t heur_subdissector_list;
919
920 static void add_uri (proto_tree *, packet_info *, tvbuff_t *, guint, guint);
921 static void add_headers (proto_tree *, tvbuff_t *);
922 static int add_well_known_header (proto_tree *, tvbuff_t *, int, guint8);
923 static int add_unknown_header (proto_tree *, tvbuff_t *, int, guint8);
924 static int add_application_header (proto_tree *, tvbuff_t *, int);
925 static void add_accept_header (proto_tree *, tvbuff_t *, int,
926     tvbuff_t *, value_type_t, int);
927 static void add_accept_xxx_header (proto_tree *, tvbuff_t *, int,
928     tvbuff_t *, value_type_t, int, int, int, const value_string *,
929     const char *);
930 static void add_accept_ranges_header (proto_tree *, tvbuff_t *, int,
931     tvbuff_t *, value_type_t, int);
932 static void add_cache_control_header (proto_tree *, tvbuff_t *, int,
933     tvbuff_t *, value_type_t, int);
934 static int add_cache_control_field_name (proto_tree *, tvbuff_t *, int, guint);
935 static void add_connection_header (proto_tree *, tvbuff_t *, int,
936     tvbuff_t *, value_type_t, int);
937 static void add_content_type_value (proto_tree *, tvbuff_t *, int, int,
938     tvbuff_t *, value_type_t, int, int, int, guint *, const char **);
939 static void add_wap_application_id_header (proto_tree *, tvbuff_t *, int,
940     tvbuff_t *, value_type_t, int);
941 static void add_integer_value_header_common (proto_tree *, tvbuff_t *, int,
942     tvbuff_t *, value_type_t, int, int, guint8, const value_string *);
943 static void add_integer_value_header (proto_tree *, tvbuff_t *, int,
944     tvbuff_t *, value_type_t, int, int, guint8);
945 static void add_string_value_header_common (proto_tree *, tvbuff_t *, int,
946     tvbuff_t *, value_type_t, int, int, guint8, const value_string *);
947 static void add_string_value_header (proto_tree *, tvbuff_t *, int,
948     tvbuff_t *, value_type_t, int, int, guint8);
949 static void add_quoted_string_value_header (proto_tree *, tvbuff_t *, int,
950     tvbuff_t *, value_type_t, int, int, guint8);
951 static void add_date_value_header (proto_tree *, tvbuff_t *, int,
952     tvbuff_t *, value_type_t, int, int, guint8);
953 static int add_parameter (proto_tree *, tvbuff_t *, int);
954 static int add_untyped_parameter (proto_tree *, tvbuff_t *, int, int);
955 static int add_parameter_charset (proto_tree *, tvbuff_t *, int, int);
956 static int add_constrained_encoding (proto_tree *, tvbuff_t *, int, int);
957 static int add_parameter_type (proto_tree *, tvbuff_t *, int, int);
958 static int add_parameter_text (proto_tree *, tvbuff_t *, int, int, int, const char *);
959 static void add_post_data (proto_tree *, tvbuff_t *, guint, const char *);
960 static void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
961 static void add_pragma_header (proto_tree *, tvbuff_t *, int, tvbuff_t *,
962     value_type_t, int);
963 static void add_transfer_encoding_header (proto_tree *, tvbuff_t *, int,
964     tvbuff_t *, value_type_t, int);
965 static void add_warning_header (proto_tree *, tvbuff_t *, int, tvbuff_t *,
966     value_type_t, int);
967 static void add_accept_application_header (proto_tree *, tvbuff_t *, int,
968     tvbuff_t *, value_type_t, int);
969 static void add_capabilities (proto_tree *tree, tvbuff_t *tvb, int type);
970 static void add_capability_vals(tvbuff_t *, gboolean, int, guint, guint, char *, size_t);
971 static value_type_t get_value_type_len (tvbuff_t *, int, guint *, int *, int *);
972 static guint get_uintvar (tvbuff_t *, guint, guint);
973 static gint get_integer (tvbuff_t *, guint, guint, value_type_t, guint *);
974
975 static int add_well_known_openwave_header (proto_tree *, tvbuff_t *, int, guint8);
976 static void add_openwave_integer_value_header (proto_tree *, tvbuff_t *, int,
977     tvbuff_t *, value_type_t, int, int, guint8);
978 static void add_openwave_string_value_header (proto_tree *, tvbuff_t *, int,
979     tvbuff_t *, value_type_t, int, int, guint8);
980
981
982 /* Code to actually dissect the packets */
983 static void
984 dissect_redirect(tvbuff_t *tvb, int offset, packet_info *pinfo,
985     proto_tree *tree, dissector_handle_t dissector_handle)
986 {
987         guint8 flags;
988         proto_item *ti;
989         proto_tree *flags_tree;
990         guint8 bearer_type;
991         guint8 address_flags_len;
992         int address_len;
993         proto_tree *atf_tree;
994         guint16 port_num;
995         guint32 address_ipv4;
996         struct e_in6_addr address_ipv6;
997         address redir_address;
998         conversation_t *conv;
999
1000         flags = tvb_get_guint8 (tvb, offset);
1001         if (tree) {
1002                 ti = proto_tree_add_uint (tree, hf_wsp_redirect_flags,
1003                     tvb, offset, 1, flags);
1004                 flags_tree = proto_item_add_subtree (ti, ett_redirect_flags);
1005                 proto_tree_add_boolean (flags_tree, hf_wsp_redirect_permanent,
1006                     tvb, offset, 1, flags);
1007                 proto_tree_add_boolean (flags_tree, hf_wsp_redirect_reuse_security_session,
1008                     tvb, offset, 1, flags);
1009         }
1010         offset++;
1011         while (tvb_reported_length_remaining (tvb, offset) > 0) {
1012                 address_flags_len = tvb_get_guint8 (tvb, offset);
1013                 if (tree) {
1014                         ti = proto_tree_add_uint (tree, hf_wsp_redirect_afl,
1015                             tvb, offset, 1, address_flags_len);
1016                         atf_tree = proto_item_add_subtree (ti, ett_redirect_afl);
1017                         proto_tree_add_boolean (atf_tree, hf_wsp_redirect_afl_bearer_type_included,
1018                             tvb, offset, 1, address_flags_len);
1019                         proto_tree_add_boolean (atf_tree, hf_wsp_redirect_afl_port_number_included,
1020                             tvb, offset, 1, address_flags_len);
1021                         proto_tree_add_uint (atf_tree, hf_wsp_redirect_afl_address_len,
1022                             tvb, offset, 1, address_flags_len);
1023                 }
1024                 offset++;
1025                 if (address_flags_len & BEARER_TYPE_INCLUDED) {
1026                         bearer_type = tvb_get_guint8 (tvb, offset);
1027                         if (tree) {
1028                                 proto_tree_add_uint (tree, hf_wsp_redirect_bearer_type,
1029                                     tvb, offset, 1, bearer_type);
1030                         }
1031                         offset++;
1032                 } else
1033                         bearer_type = 0x00;     /* XXX */
1034                 if (address_flags_len & PORT_NUMBER_INCLUDED) {
1035                         port_num = tvb_get_ntohs (tvb, offset);
1036                         if (tree) {
1037                                 proto_tree_add_uint (tree, hf_wsp_redirect_port_num,
1038                                     tvb, offset, 2, port_num);
1039                         }
1040                         offset += 2;
1041                 } else {
1042                         /*
1043                          * Redirecting to the same server port number as was
1044                          * being used, i.e. the source port number of this
1045                          * redirect.
1046                          */
1047                         port_num = pinfo->srcport;
1048                 }
1049                 address_len = address_flags_len & ADDRESS_LEN;
1050                 if (!(address_flags_len & BEARER_TYPE_INCLUDED)) {
1051                         /*
1052                          * We don't have the bearer type in the message,
1053                          * so we don't know the address type.
1054                          * (It's the same bearer type as the original
1055                          * connection.)
1056                          */
1057                         goto unknown_address_type;
1058                 }
1059
1060                 /*
1061                  * We know the bearer type, so we know the address type.
1062                  */
1063                 switch (bearer_type) {
1064
1065                 case BT_IPv4:
1066                 case BT_IS_95_CSD:
1067                 case BT_IS_95_PACKET_DATA:
1068                 case BT_ANSI_136_CSD:
1069                 case BT_ANSI_136_PACKET_DATA:
1070                 case BT_GSM_CSD:
1071                 case BT_GSM_GPRS:
1072                 case BT_GSM_USSD_IPv4:
1073                 case BT_AMPS_CDPD:
1074                 case BT_PDC_CSD:
1075                 case BT_PDC_PACKET_DATA:
1076                 case BT_IDEN_CSD:
1077                 case BT_IDEN_PACKET_DATA:
1078                 case BT_PHS_CSD:
1079                 case BT_TETRA_PACKET_DATA:
1080                         /*
1081                          * IPv4.
1082                          */
1083                         if (address_len != 4) {
1084                                 /*
1085                                  * Say what?
1086                                  */
1087                                 goto unknown_address_type;
1088                         }
1089                         tvb_memcpy(tvb, (guint8 *)&address_ipv4, offset, 4);
1090                         if (tree) {
1091                                 proto_tree_add_ipv4 (tree,
1092                                     hf_wsp_redirect_ipv4_addr,
1093                                     tvb, offset, 4, address_ipv4);
1094                         }
1095
1096                         /*
1097                          * Create a conversation so that the
1098                          * redirected session will be dissected
1099                          * as WAP.
1100                          */
1101                         redir_address.type = AT_IPv4;
1102                         redir_address.len = 4;
1103                         redir_address.data = (const guint8 *)&address_ipv4;
1104                         conv = find_conversation(&redir_address, &pinfo->dst,
1105                             PT_UDP, port_num, 0, NO_PORT_B);
1106                         if (conv == NULL) {
1107                                 conv = conversation_new(&redir_address,
1108                                     &pinfo->dst, PT_UDP, port_num, 0, NO_PORT2);
1109                         }
1110                         conversation_set_dissector(conv, dissector_handle);
1111                         break;
1112
1113                 case BT_IPv6:
1114                         /*
1115                          * IPv6.
1116                          */
1117                         if (address_len != 16) {
1118                                 /*
1119                                  * Say what?
1120                                  */
1121                                 goto unknown_address_type;
1122                         }
1123                         tvb_memcpy(tvb, (guint8 *)&address_ipv6, offset, 16);
1124                         if (tree) {
1125                                 proto_tree_add_ipv6 (tree,
1126                                     hf_wsp_redirect_ipv6_addr,
1127                                     tvb, offset, 16, (guint8 *)&address_ipv6);
1128                         }
1129
1130                         /*
1131                          * Create a conversation so that the
1132                          * redirected session will be dissected
1133                          * as WAP.
1134                          */
1135                         redir_address.type = AT_IPv6;
1136                         redir_address.len = 16;
1137                         redir_address.data = (const guint8 *)&address_ipv4;
1138                         conv = find_conversation(&redir_address, &pinfo->dst,
1139                             PT_UDP, port_num, 0, NO_PORT_B);
1140                         if (conv == NULL) {
1141                                 conv = conversation_new(&redir_address,
1142                                     &pinfo->dst, PT_UDP, port_num, 0, NO_PORT2);
1143                         }
1144                         conversation_set_dissector(conv, dissector_handle);
1145                         break;
1146
1147                 unknown_address_type:
1148                 default:
1149                         if (address_len != 0) {
1150                                 if (tree) {
1151                                         proto_tree_add_item (tree,
1152                                             hf_wsp_redirect_addr,
1153                                             tvb, offset, address_len,
1154                                             bo_little_endian);
1155                                 }
1156                         }
1157                         break;
1158                 }
1159                 offset += address_len;
1160         }
1161 }
1162
1163 static void
1164 dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1165     dissector_handle_t dissector_handle, gboolean is_connectionless)
1166 {
1167         int offset = 0;
1168
1169         guint8 pdut;
1170         guint count = 0;
1171         guint value = 0;
1172         guint uriLength = 0;
1173         guint uriStart = 0;
1174         guint capabilityLength = 0;
1175         guint capabilityStart = 0;
1176         guint headersLength = 0;
1177         guint headerLength = 0;
1178         guint headerStart = 0;
1179         guint nextOffset = 0;
1180         guint contentTypeStart = 0;
1181         guint contentType = 0;
1182         const char *contentTypeStr;
1183         tvbuff_t *tmp_tvb;
1184
1185 /* Set up structures we will need to add the protocol subtree and manage it */
1186         proto_item *ti;
1187         proto_tree *wsp_tree = NULL;
1188 /*      proto_tree *wsp_header_fixed; */
1189         
1190 /* This field shows up as the "Info" column in the display; you should make
1191    it, if possible, summarize what's in the packet, so that a user looking
1192    at the list of packets can tell what type of packet it is. */
1193     
1194         /* Connection-less mode has a TID first */
1195         if (is_connectionless)
1196         {
1197                 offset++;
1198         };
1199
1200         /* Find the PDU type */
1201         pdut = tvb_get_guint8 (tvb, offset);
1202
1203         /* Develop the string to put in the Info column */
1204         if (check_col(pinfo->cinfo, COL_INFO))
1205         {
1206                 col_append_fstr(pinfo->cinfo, COL_INFO, "WSP %s",
1207                         val_to_str (pdut, vals_pdu_type, "Unknown PDU type (0x%02x)"));
1208         };
1209
1210 /* In the interest of speed, if "tree" is NULL, don't do any work not
1211    necessary to generate protocol tree items. */
1212         if (tree) {
1213                 ti = proto_tree_add_item(tree, proto_wsp, tvb, 0, -1,
1214                     bo_little_endian);
1215                 wsp_tree = proto_item_add_subtree(ti, ett_wsp);
1216
1217 /* Code to process the packet goes here */
1218 /*
1219                 wsp_header_fixed = proto_item_add_subtree(ti, ett_header );
1220 */
1221
1222                 /* Add common items: only TID and PDU Type */
1223
1224                 /* If this is connectionless, then the TID Field is always first */
1225                 if (is_connectionless)
1226                 {
1227                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_tid,tvb,
1228                                 0,1,bo_little_endian);
1229                 }
1230
1231                 ti = proto_tree_add_item(
1232                                 wsp_tree,               /* tree */
1233                                 hf_wsp_header_pdu_type, /* id */
1234                                 tvb, 
1235                                 offset,                 /* start of high light */
1236                                 1,                      /* length of high light */
1237                                 bo_little_endian        /* value */
1238                      );
1239         }
1240         offset++;
1241
1242         switch (pdut)
1243         {
1244                 case CONNECT:
1245                 case CONNECTREPLY:
1246                 case RESUME:
1247                         if (tree) {
1248                                 if (pdut == CONNECT)
1249                                 {
1250                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
1251                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
1252                                         offset++;
1253                                 } else {
1254                                         count = 0;      /* Initialise count */
1255                                         value = tvb_get_guintvar (tvb, offset, &count);
1256                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
1257                                         offset += count;
1258                                 }
1259                                 capabilityStart = offset;
1260                                 count = 0;      /* Initialise count */
1261                                 capabilityLength = tvb_get_guintvar (tvb, offset, &count);
1262                                 offset += count;
1263                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
1264
1265                                 if (pdut != RESUME)
1266                                 {
1267                                         count = 0;      /* Initialise count */
1268                                         headerLength = tvb_get_guintvar (tvb, offset, &count);
1269                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset,count,headerLength);
1270                                         offset += count;
1271                                         capabilityStart = offset;
1272                                         headerStart = capabilityStart + capabilityLength;
1273                                 } else {
1274                                                 /* Resume computes the headerlength by remaining bytes */
1275                                         capabilityStart = offset;
1276                                         headerStart = capabilityStart + capabilityLength;
1277                                         headerLength = tvb_reported_length_remaining (tvb, headerStart);
1278                                 }
1279                                 if (capabilityLength > 0)
1280                                 {
1281                                         tmp_tvb = tvb_new_subset (tvb, offset, capabilityLength, capabilityLength);
1282                                         add_capabilities (wsp_tree, tmp_tvb, pdut);
1283                                         offset += capabilityLength;
1284                                 }
1285
1286                                 if (headerLength > 0)
1287                                 {
1288                                         tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
1289                                         add_headers (wsp_tree, tmp_tvb);
1290                                 }
1291                         }
1292
1293                         break;
1294
1295                 case REDIRECT:
1296                         dissect_redirect(tvb, offset, pinfo, wsp_tree,
1297                           dissector_handle);
1298                         break;
1299
1300                 case DISCONNECT:
1301                 case SUSPEND:
1302                         if (tree) {
1303                                 count = 0;      /* Initialise count */
1304                                 value = tvb_get_guintvar (tvb, offset, &count);
1305                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
1306                         }
1307                         break;
1308
1309                 case GET:
1310                         count = 0;      /* Initialise count */
1311                                 /* Length of URI and size of URILen field */
1312                         value = tvb_get_guintvar (tvb, offset, &count);
1313                         nextOffset = offset + count;
1314                         add_uri (wsp_tree, pinfo, tvb, offset, nextOffset);
1315                         if (tree) {
1316                                 offset += (value+count); /* VERIFY */
1317                                 tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
1318                                 add_headers (wsp_tree, tmp_tvb);
1319                         }
1320                         break;
1321
1322                 case POST:
1323                         uriStart = offset;
1324                         count = 0;      /* Initialise count */
1325                         uriLength = tvb_get_guintvar (tvb, offset, &count);
1326                         headerStart = uriStart+count;
1327                         count = 0;      /* Initialise count */
1328                         headersLength = tvb_get_guintvar (tvb, headerStart, &count);
1329                         offset = headerStart + count;
1330
1331                         add_uri (wsp_tree, pinfo, tvb, uriStart, offset);
1332                         if (tree) {
1333                                 offset += uriLength;
1334
1335                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headersLength);
1336
1337                                 if (headersLength == 0)
1338                                         break;
1339
1340                                 contentTypeStart = offset;
1341                                 nextOffset = add_content_type (wsp_tree,
1342                                     tvb, offset, &contentType,
1343                                     &contentTypeStr);
1344
1345                                 /* Add headers subtree that will hold the headers fields */
1346                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1347                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1348                                 if (headerLength > 0)
1349                                 {
1350                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1351                                         add_headers (wsp_tree, tmp_tvb);
1352                                 }
1353
1354                                 /* TODO: Post DATA */
1355                                 /* Runs from start of headers+headerLength to end of frame */
1356                                 offset = nextOffset+headerLength;
1357                                 tmp_tvb = tvb_new_subset (tvb, offset, tvb_reported_length (tvb)-offset, tvb_reported_length (tvb)-offset);
1358                                 add_post_data (wsp_tree, tmp_tvb,
1359                                     contentType, contentTypeStr);
1360                         }
1361                         if (tvb_reported_length_remaining(tvb, headerStart + count + uriLength + headersLength) > 0)
1362                         {
1363                                 tmp_tvb = tvb_new_subset (tvb, headerStart + count + uriLength + headersLength, -1, -1);
1364                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1365                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1366                         }
1367                         break;
1368
1369                 case REPLY:
1370                         count = 0;      /* Initialise count */
1371                         headersLength = tvb_get_guintvar (tvb, offset+1, &count);
1372                         headerStart = offset + count + 1;
1373                         if (tree) {
1374                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
1375                                 nextOffset = offset + 1 + count;
1376                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,headersLength);
1377
1378                                 if (headersLength == 0)
1379                                         break;
1380
1381                                 contentTypeStart = nextOffset;
1382                                 nextOffset = add_content_type (wsp_tree,
1383                                     tvb, nextOffset, &contentType,
1384                                     &contentTypeStr);
1385
1386                                 /* Add headers subtree that will hold the headers fields */
1387                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1388                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1389                                 if (headerLength > 0)
1390                                 {
1391                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1392                                         add_headers (wsp_tree, tmp_tvb);
1393                                 }
1394                                 offset += count+headersLength+1;
1395
1396                                 /* TODO: Data - decode WMLC */
1397                                 /* Runs from offset+1+count+headerLength+1 to end of frame */
1398                                 if (tvb_reported_length_remaining (tvb, offset) > 0)
1399                                 {
1400                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,-1,bo_little_endian);
1401                                 }
1402                         }
1403                         if (tvb_reported_length_remaining(tvb, headerStart + headersLength) > 0)
1404                         {
1405                                 tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength, -1, -1);
1406                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1407                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1408                         }
1409                         break;
1410
1411                 case PUSH:
1412                 case CONFIRMEDPUSH:
1413                         count = 0;      /* Initialise count */
1414                         headersLength = tvb_get_guintvar (tvb, offset, &count);
1415                         headerStart = offset + count;
1416
1417                         if (tree) {
1418                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset,count,headersLength);
1419
1420                                 if (headersLength == 0)
1421                                         break;
1422
1423                                 offset += count;
1424                                 contentTypeStart = offset;
1425                                 nextOffset = add_content_type (wsp_tree,
1426                                     tvb, offset, &contentType,
1427                                     &contentTypeStr);
1428
1429                                 /* Add headers subtree that will hold the headers fields */
1430                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1431                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1432                                 if (headerLength > 0)
1433                                 {
1434                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1435                                         add_headers (wsp_tree, tmp_tvb);
1436                                 }
1437                                 offset += headersLength;
1438
1439                                 /* Push DATA */
1440                                 if (tvb_reported_length_remaining (tvb, offset) > 0)
1441                                 {
1442                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_push_data,tvb,offset,-1,bo_little_endian);
1443                                 }
1444                         }
1445                         if (tvb_reported_length_remaining(tvb, headerStart + headersLength) > 0)
1446                         {
1447                                 tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength, -1, -1);
1448                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1449                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1450                         }
1451                         break;
1452
1453         }
1454 }
1455
1456 /*
1457  * Called directly from UDP.
1458  * Put "WSP" into the "Protocol" column.
1459  */
1460 static void
1461 dissect_wsp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1462 {
1463         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1464                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WSP" );
1465         if (check_col(pinfo->cinfo, COL_INFO))
1466                 col_clear(pinfo->cinfo, COL_INFO);
1467
1468         dissect_wsp_common(tvb, pinfo, tree, wsp_fromudp_handle, TRUE);
1469 }
1470
1471 /*
1472  * Called from a higher-level WAP dissector, in connection-oriented mode.
1473  * Leave the "Protocol" column alone - the dissector calling us should
1474  * have set it.
1475  */
1476 static void
1477 dissect_wsp_fromwap_co(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1478 {
1479         /*
1480          * XXX - what about WTLS->WTP->WSP?
1481          */
1482         dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, FALSE);
1483 }
1484
1485 /*
1486  * Called from a higher-level WAP dissector, in connectionless mode.
1487  * Leave the "Protocol" column alone - the dissector calling us should
1488  * have set it.
1489  */
1490 static void
1491 dissect_wsp_fromwap_cl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1492 {
1493         /*
1494          * XXX - what about WTLS->WSP?
1495          */
1496         if (check_col(pinfo->cinfo, COL_INFO))
1497         {
1498                 col_clear(pinfo->cinfo, COL_INFO);
1499         }
1500         dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, TRUE);
1501 }
1502
1503 static void
1504 add_uri (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
1505 {
1506         proto_item *ti;
1507         char *newBuffer;
1508
1509         guint count = 0;
1510         guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
1511
1512         if (tree)
1513                 ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
1514
1515         newBuffer = g_malloc (uriLen+2);
1516         newBuffer[0] = ' ';  /* This is for COL_INFO */
1517         strncpy (newBuffer+1, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
1518         newBuffer[uriLen+1] = 0;
1519         if (tree)
1520                 ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer+1);
1521         if (check_col(pinfo->cinfo, COL_INFO)) {
1522                 col_append_str(pinfo->cinfo, COL_INFO, newBuffer);
1523         };
1524         g_free (newBuffer);
1525 }
1526
1527 static void
1528 add_headers (proto_tree *tree, tvbuff_t *tvb)
1529 {
1530         proto_item *ti;
1531         proto_tree *wsp_headers;
1532         guint offset = 0;
1533         guint headersLen = tvb_reported_length (tvb);
1534         guint headerStart = 0;
1535         guint peek = 0;
1536         guint pageCode = 1;
1537
1538 #ifdef DEBUG
1539         fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, headersLen);
1540 #endif
1541
1542         /* End of buffer */
1543         if (headersLen <= 0)
1544         {
1545                 return;
1546         }
1547
1548 #ifdef DEBUG
1549         fprintf (stderr, "dissect_wsp: Headers to process\n");
1550 #endif
1551
1552         ti = proto_tree_add_item (tree, hf_wsp_headers_section,tvb,offset,headersLen,bo_little_endian);
1553         wsp_headers = proto_item_add_subtree( ti, ett_headers );
1554
1555         /* Parse Headers */
1556
1557         while (offset < headersLen)
1558         {
1559                 /* Loop round each header */
1560                 headerStart = offset;
1561                 peek = tvb_get_guint8 (tvb, headerStart);
1562
1563                 if (peek < 32)          /* Short-cut shift delimiter */
1564                 {
1565                         pageCode = peek;
1566                         proto_tree_add_uint (wsp_headers,
1567                             hf_wsp_header_shift_code, tvb, offset, 1,
1568                             pageCode);
1569                         offset += 1;
1570                         continue;
1571                 }
1572                 else if (peek == 0x7F)  /* Shift delimiter */
1573                 {
1574                         pageCode = tvb_get_guint8(tvb, offset+1);
1575                         proto_tree_add_uint (wsp_headers,
1576                             hf_wsp_header_shift_code, tvb, offset, 2,
1577                             pageCode);
1578                         offset += 2;
1579                         continue;
1580                 }
1581                 else if (peek < 127)
1582                 {
1583 #ifdef DEBUG
1584                         fprintf (stderr, "dissect_wsp: header: application-header start %d (0x%02X)\n", peek, peek);
1585 #endif
1586                         /*
1587                          * Token-text, followed by Application-specific-value.
1588                          */
1589                         offset = add_application_header (wsp_headers, tvb,
1590                             headerStart);
1591                 }
1592                 else if (peek & 0x80)
1593                 {
1594 #ifdef DEBUG
1595                         fprintf (stderr, "dissect_wsp: header: well-known %d (0x%02X)\n", peek, peek);
1596 #endif
1597                         /*
1598                          * Well-known-header; the lower 7 bits of "peek"
1599                          * are the header code.
1600                          */
1601                         switch (pageCode) {
1602                         case 1:
1603                                 offset = add_well_known_header (wsp_headers,
1604                                     tvb, headerStart, peek & 0x7F);
1605                                 break;
1606
1607                         case 2:
1608                         case 16:
1609                                 offset = add_well_known_openwave_header (wsp_headers,
1610                                     tvb, headerStart, peek & 0x7F);
1611                                 break;
1612
1613                         default:
1614                                 offset = add_unknown_header (wsp_headers,
1615                                     tvb, headerStart, peek & 0x7F);
1616                                 break;
1617                         }
1618                 }
1619         }
1620 }
1621
1622 static int
1623 add_well_known_header (proto_tree *tree, tvbuff_t *tvb, int offset,
1624     guint8 headerType)
1625 {
1626         int headerStart;
1627         value_type_t valueType;
1628         int headerLen;
1629         guint valueLen;
1630         int valueStart;
1631         tvbuff_t *header_buff;
1632         tvbuff_t *value_buff;
1633
1634 #ifdef DEBUG
1635         fprintf (stderr, "dissect_wsp: Got header 0x%02x\n", headerType);
1636 #endif
1637         headerStart = offset;
1638
1639         /*
1640          * Skip the Short-Integer header type.
1641          */
1642         offset++;
1643
1644         /*
1645          * Get the value type and length (or, if the type is VALUE_IN_LEN,
1646          * meaning the value is a Short-integer, get the value type
1647          * and the value itself).
1648          */ 
1649         valueType = get_value_type_len (tvb, offset, &valueLen,
1650             &valueStart, &offset);
1651         headerLen = offset - headerStart;
1652
1653         /*
1654          * Get a tvbuff for the entire header.
1655          * XXX - cut the actual length short so that it doesn't run
1656          * past the actual length of tvb.
1657          */
1658         header_buff = tvb_new_subset (tvb, headerStart, headerLen,
1659             headerLen);
1660
1661         /*
1662          * If the value wasn't in the length, get a tvbuff for the value.
1663          * XXX - can valueLen be 0?
1664          * XXX - cut the actual length short so that it doesn't run
1665          * past the actual length of tvb.
1666          */
1667         if (valueType != VALUE_IN_LEN) {
1668                 value_buff = tvb_new_subset (tvb, valueStart, valueLen,
1669                     valueLen);
1670         } else {
1671                 /*
1672                  * XXX - when the last dissector is tvbuffified,
1673                  * so that NULL is no longer a valid tvb pointer
1674                  * value in "proto_tree_add" calls, just
1675                  * set "value_buff" to NULL.
1676                  *
1677                  * XXX - can we already do that?  I.e., will that
1678                  * cause us always to crash if we mistakenly try
1679                  * to fetch the value of a VALUE_IN_LEN item?
1680                  */
1681                 value_buff = tvb_new_subset (tvb, headerStart, 0, 0);
1682         }
1683
1684         switch (headerType) {
1685
1686         case FN_ACCEPT:                 /* Accept */
1687                 add_accept_header (tree, header_buff, headerLen,
1688                     value_buff, valueType, valueLen);
1689                 break;
1690
1691         case FN_ACCEPT_CHARSET_DEP:     /* Accept-Charset */
1692                 /*
1693                  * XXX - should both encoding versions 1.1 and
1694                  * 1.3 be handled this way?
1695                  */
1696                 add_accept_xxx_header (tree, header_buff, headerLen,
1697                     value_buff, valueType, valueLen,
1698                     hf_wsp_header_accept_charset,
1699                     hf_wsp_header_accept_charset_str,
1700                     vals_character_sets, "Unknown charset (%u)");
1701                 break;
1702
1703         case FN_ACCEPT_LANGUAGE:        /* Accept-Language */
1704                 add_accept_xxx_header (tree, header_buff, headerLen,
1705                     value_buff, valueType, valueLen,
1706                     hf_wsp_header_accept_language,
1707                     hf_wsp_header_accept_language_str,
1708                     vals_languages, "Unknown language (%u)");
1709                 break;
1710
1711         case FN_ACCEPT_RANGES:          /* Accept-Ranges */
1712                 add_accept_ranges_header (tree, header_buff, headerLen,
1713                     value_buff, valueType, valueLen);
1714                 break;
1715
1716         case FN_AGE:                    /* Age */
1717                 add_integer_value_header (tree, header_buff, headerLen,
1718                     value_buff, valueType, valueLen, hf_wsp_header_age,
1719                     headerType);
1720                 break;
1721
1722         case FN_CACHE_CONTROL_DEP:      /* Cache-Control */
1723         case FN_CACHE_CONTROL:
1724         case FN_CACHE_CONTROL14:
1725                 /*
1726                  * XXX - is the only difference in the three different
1727                  * versions (1.1, 1.3, 1.4) really only S_MAXAGE?
1728                  */
1729                 add_cache_control_header (tree, header_buff, headerLen,
1730                     value_buff, valueType, valueLen);
1731                 break;
1732                                 
1733         case FN_CONNECTION:     /* Connection */
1734                 add_connection_header (tree, header_buff, headerLen,
1735                     value_buff, valueType, valueLen);
1736                 break;
1737
1738         case FN_CONTENT_LENGTH:         /* Content-Length */
1739                 add_integer_value_header (tree, header_buff, headerLen,
1740                     value_buff, valueType, valueLen,
1741                     hf_wsp_header_content_length,
1742                     headerType);
1743                 break;
1744                                 
1745         case FN_DATE:                   /* Date */
1746                 add_date_value_header (tree, header_buff, headerLen,
1747                     value_buff, valueType, valueLen,
1748                     hf_wsp_header_date, headerType);
1749                 break;
1750
1751         case FN_ETAG:                   /* Etag */
1752                 add_string_value_header (tree, header_buff, headerLen,
1753                     value_buff, valueType, valueLen,
1754                     hf_wsp_header_etag, headerType);
1755                 break;
1756
1757         case FN_EXPIRES:                /* Expires */
1758                 add_date_value_header (tree, header_buff, headerLen,
1759                     value_buff, valueType, valueLen,
1760                     hf_wsp_header_expires, headerType);
1761                 break;
1762
1763         case FN_IF_MODIFIED_SINCE:      /* If-Modified-Since */
1764                 add_date_value_header (tree, header_buff, headerLen,
1765                     value_buff, valueType, valueLen,
1766                     hf_wsp_header_if_modified_since, headerType);
1767                 break;
1768                                 
1769         case FN_LOCATION:               /* Location */
1770                 add_string_value_header (tree, header_buff, headerLen,
1771                     value_buff, valueType, valueLen,
1772                     hf_wsp_header_location, headerType);
1773                 break;
1774
1775         case FN_LAST_MODIFIED:          /* Last-Modified */
1776                 add_date_value_header (tree, header_buff, headerLen,
1777                     value_buff, valueType, valueLen,
1778                     hf_wsp_header_last_modified, headerType);
1779                 break;
1780                                 
1781         case FN_PRAGMA:                 /* Pragma */
1782                 add_pragma_header (tree, header_buff, headerLen,
1783                     value_buff, valueType, valueLen);
1784                 break;
1785                                 
1786         case FN_SERVER:                 /* Server */
1787                 add_string_value_header (tree, header_buff, headerLen,
1788                     value_buff, valueType, valueLen,
1789                     hf_wsp_header_server, headerType);
1790                 break;
1791
1792         case FN_TRANSFER_ENCODING:      /* Transfer-Encoding */
1793                 add_transfer_encoding_header (tree, header_buff, headerLen,
1794                     value_buff, valueType, valueLen);
1795                 break;
1796
1797         case FN_USER_AGENT:             /* User-Agent */
1798                 add_string_value_header (tree, header_buff, headerLen,
1799                     value_buff, valueType, valueLen,
1800                     hf_wsp_header_user_agent, headerType);
1801                 break;
1802
1803         case FN_VIA:                    /* Via */
1804                 add_string_value_header (tree, header_buff, headerLen,
1805                     value_buff, valueType, valueLen,
1806                     hf_wsp_header_via, headerType);
1807                 break;
1808
1809         case FN_WARNING:                /* Warning */
1810                 add_warning_header (tree, header_buff, headerLen,
1811                     value_buff, valueType, valueLen);
1812                 break;
1813
1814         case FN_ACCEPT_APPLICATION:     /* Accept-Application */
1815                 add_accept_application_header (tree, header_buff, headerLen,
1816                     value_buff, valueType, valueLen);
1817                 break;
1818
1819         case FN_BEARER_INDICATION:      /* Bearer-Indication */
1820                 add_integer_value_header (tree, header_buff, headerLen,
1821                     value_buff, valueType, valueLen,
1822                     hf_wsp_header_bearer_indication, headerType);
1823                 break;
1824
1825         case FN_PROFILE:                /* Profile */
1826                 add_string_value_header (tree, header_buff, headerLen,
1827                     value_buff, valueType, valueLen,
1828                     hf_wsp_header_profile, headerType);
1829                 break;
1830
1831         case FN_X_WAP_APPLICATION_ID:   /* X-Wap-Application-Id */
1832                 add_wap_application_id_header (tree, header_buff, headerLen,
1833                     value_buff, valueType, valueLen);
1834                 break;
1835
1836         case FN_CONTENT_ID:             /* Content-ID   */
1837                 add_quoted_string_value_header (tree, header_buff, headerLen,
1838                     value_buff, valueType, valueLen,
1839                     hf_wsp_header_content_ID, headerType);
1840                 break;
1841
1842         default:
1843                 proto_tree_add_text (tree, header_buff, 0, headerLen,
1844                     "Unsupported Header: %s",
1845                     val_to_str (headerType, vals_field_names, "Unknown (0x%02X)"));
1846                 break;
1847         }
1848         return offset;
1849 }
1850
1851
1852 static int
1853 add_well_known_openwave_header (proto_tree *tree, tvbuff_t *tvb, int offset,
1854     guint8 headerType)
1855 {
1856         int headerStart;
1857         value_type_t valueType;
1858         int headerLen;
1859         guint valueLen;
1860         int valueStart;
1861         tvbuff_t *header_buff;
1862         tvbuff_t *value_buff;
1863
1864 #ifdef DEBUG
1865         fprintf (stderr, "dissect_wsp: Got Openwave header 0x%02x\n", headerType);
1866 #endif
1867         headerStart = offset;
1868
1869         /*
1870          * Skip the Short-Integer header type.
1871          */
1872         offset++;
1873
1874         /*
1875          * Get the value type and length (or, if the type is VALUE_IN_LEN,
1876          * meaning the value is a Short-integer, get the value type
1877          * and the value itself).
1878          */ 
1879         valueType = get_value_type_len (tvb, offset, &valueLen,
1880             &valueStart, &offset);
1881         headerLen = offset - headerStart;
1882
1883         /*
1884          * Get a tvbuff for the entire header.
1885          * XXX - cut the actual length short so that it doesn't run
1886          * past the actual length of tvb.
1887          */
1888         header_buff = tvb_new_subset (tvb, headerStart, headerLen,
1889             headerLen);
1890
1891         /*
1892          * If the value wasn't in the length, get a tvbuff for the value.
1893          * XXX - can valueLen be 0?
1894          * XXX - cut the actual length short so that it doesn't run
1895          * past the actual length of tvb.
1896          */
1897         if (valueType != VALUE_IN_LEN) {
1898                 value_buff = tvb_new_subset (tvb, valueStart, valueLen,
1899                     valueLen);
1900         } else {
1901                 /*
1902                  * XXX - when the last dissector is tvbuffified,
1903                  * so that NULL is no longer a valid tvb pointer
1904                  * value in "proto_tree_add" calls, just
1905                  * set "value_buff" to NULL.
1906                  *
1907                  * XXX - can we already do that?  I.e., will that
1908                  * cause us always to crash if we mistakenly try
1909                  * to fetch the value of a VALUE_IN_LEN item?
1910                  */
1911                 value_buff = tvb_new_subset (tvb, headerStart, 0, 0);
1912         }
1913
1914         switch (headerType) {
1915
1916 /*      case FN_OPENWAVE_PROXY_PUSH_ADDR:       / x-up-proxy-push-addr */
1917 /*              add_openwave_push_address_header (tree, header_buff, headerLen, */
1918 /*                  value_buff, valueType, valueLen); */
1919 /*              break; */
1920
1921         case FN_OPENWAVE_PROXY_PUSH_ACCEPT:     /* x-up-proxy-push-accept */
1922                 add_accept_header (tree, header_buff, headerLen,
1923                     value_buff, valueType, valueLen);
1924                 break;
1925
1926         case FN_OPENWAVE_PROXY_PUSH_SEQ:        /* x-up-proxy-push-seq */
1927                 add_openwave_integer_value_header (tree, header_buff, headerLen,
1928                     value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_push_seq,
1929                     headerType);
1930                 break;
1931
1932         case FN_OPENWAVE_PROXY_NOTIFY:          /* x-up-proxy-notify */
1933                 add_openwave_integer_value_header (tree, header_buff, headerLen,
1934                     value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_notify,
1935                     headerType);
1936                 break;
1937
1938         case FN_OPENWAVE_PROXY_OPERATOR_DOMAIN: /* x-up-proxy-operator-domain */
1939                 add_openwave_string_value_header (tree, header_buff, headerLen,
1940                     value_buff, valueType, valueLen,
1941                     hf_wsp_header_openwave_proxy_operator_domain, headerType);
1942                 break;
1943
1944         case FN_OPENWAVE_PROXY_HOME_PAGE:       /* x-up-proxy-home-page */
1945                 add_openwave_string_value_header (tree, header_buff, headerLen,
1946                     value_buff, valueType, valueLen,
1947                     hf_wsp_header_openwave_proxy_home_page, headerType);
1948                 break;
1949
1950         case FN_OPENWAVE_DEVCAP_HAS_COLOR:      /* x-up-devcap-has-color */
1951                 add_openwave_integer_value_header (tree, header_buff, headerLen,
1952                     value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_has_color,
1953                     headerType);
1954                 break;
1955
1956         case FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS:   /* x-up-devcap-num-softkeys */
1957                 add_openwave_integer_value_header (tree, header_buff, headerLen,
1958                     value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_num_softkeys,
1959                     headerType);
1960                 break;
1961
1962         case FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE:   /* x-up-devcap-softkey-size */
1963                 add_openwave_integer_value_header (tree, header_buff, headerLen,
1964                     value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_softkey_size,
1965                     headerType);
1966                 break;
1967
1968 /*      case FN_OPENWAVE_DEVCAP_SCREEN_CHARS:   / x-up-devcap-screen-chars */
1969 /*              add_openwave_integer_value_header (tree, header_buff, headerLen, */
1970 /*                  value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_screen_chars, */
1971 /*                  headerType); */
1972 /*              break; */
1973
1974 /*      case FN_OPENWAVE_DEVCAP_SCREEN_PIXELS:  / x-up-devcap-screen-pixels */
1975 /*              add_openwave_integer_value_header (tree, header_buff, headerLen, */
1976 /*                  value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_screen_pixels, */
1977 /*                  headerType); */
1978 /*              break; */
1979
1980 /*      case FN_OPENWAVE_DEVCAP_EM_SIZE:        / x-up-devcap-em-size */
1981 /*              add_openwave_integer_value_header (tree, header_buff, headerLen, */
1982 /*                  value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_em_size, */
1983 /*                  headerType); */
1984 /*              break; */
1985
1986         case FN_OPENWAVE_DEVCAP_SCREEN_DEPTH:   /* x-up-devcap-screen-depth */
1987                 add_openwave_integer_value_header (tree, header_buff, headerLen,
1988                     value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_screen_depth,
1989                     headerType);
1990                 break;
1991
1992         case FN_OPENWAVE_DEVCAP_IMMED_ALERT:    /* x-up-devcap-immed-alert */
1993                 add_openwave_integer_value_header (tree, header_buff, headerLen,
1994                     value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_immed_alert,
1995                     headerType);
1996                 break;
1997
1998         case FN_OPENWAVE_PROXY_NET_ASK:         /* x-up-proxy-net-ask */
1999                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2000                     value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_net_ask,
2001                     headerType);
2002                 break;
2003
2004         case FN_OPENWAVE_PROXY_UPLINK_VERSION:          /* x-up-proxy-uplink-version */
2005                 add_openwave_string_value_header (tree, header_buff, headerLen,
2006                     value_buff, valueType, valueLen,
2007                     hf_wsp_header_openwave_proxy_uplink_version, headerType);
2008                 break;
2009
2010         case FN_OPENWAVE_PROXY_TOD:             /* x-up-proxy-tod */
2011                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2012                     value_buff, valueType, valueLen,
2013                     hf_wsp_header_openwave_proxy_tod, headerType);
2014                 break;
2015
2016         case FN_OPENWAVE_PROXY_BA_ENABLE:               /* x-up-proxy-ba-enable */
2017                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2018                     value_buff, valueType, valueLen,
2019                     hf_wsp_header_openwave_proxy_ba_enable, headerType);
2020                 break;
2021
2022         case FN_OPENWAVE_PROXY_BA_REALM:                /* x-up-proxy-ba-realm */
2023                 add_openwave_string_value_header (tree, header_buff, headerLen,
2024                     value_buff, valueType, valueLen,
2025                     hf_wsp_header_openwave_proxy_ba_realm, headerType);
2026                 break;
2027
2028         case FN_OPENWAVE_PROXY_REDIRECT_ENABLE:         /* x-up-proxy-redirect-enable */
2029                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2030                     value_buff, valueType, valueLen,
2031                     hf_wsp_header_openwave_proxy_redirect_enable, headerType);
2032                 break;
2033
2034         case FN_OPENWAVE_PROXY_REQUEST_URI:             /* x-up-proxy-request-uri */
2035                 add_openwave_string_value_header (tree, header_buff, headerLen,
2036                     value_buff, valueType, valueLen,
2037                     hf_wsp_header_openwave_proxy_request_uri, headerType);
2038                 break;
2039
2040 /*      case FN_OPENWAVE_PROXY_REDIRECT_STATUS:         / x-up-proxy-redirect-status */
2041 /*              add_openwave_integer_value_header (tree, header_buff, headerLen, */
2042 /*                  value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_redirect_status, */
2043 /*                  headerType); */
2044 /*              break; */
2045
2046         case FN_OPENWAVE_PROXY_TRANS_CHARSET:           /* x-up-proxy-trans-charset */
2047                 add_accept_xxx_header (tree, header_buff, headerLen,
2048                     value_buff, valueType, valueLen,
2049                     hf_wsp_header_openwave_proxy_trans_charset,
2050                     hf_wsp_header_openwave_proxy_trans_charset_str,
2051                     vals_character_sets, "Unknown charset (%u)");
2052                 break;
2053
2054         case FN_OPENWAVE_PROXY_LINGER:                  /* x-up-proxy-linger */
2055                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2056                     value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_linger,
2057                     headerType);
2058                 break;
2059
2060 /*      case FN_OPENWAVE_PROXY_CLIENT_ID:               / x-up-proxy-client-id */
2061 /*              add_openwave_string_value_header (tree, header_buff, headerLen, */
2062 /*                  value_buff, valueType, valueLen, */
2063 /*                  hf_wsp_header_openwave_proxy_client_id, headerType); */
2064 /*              break; */
2065
2066         case FN_OPENWAVE_PROXY_ENABLE_TRUST:            /* x-up-proxy-enable-trust */
2067                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2068                     value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_enable_trust,
2069                     headerType);
2070                 break;
2071
2072         case FN_OPENWAVE_PROXY_TRUST_OLD:               /* x-up-proxy-trust old value */
2073                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2074                     value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_trust_old,
2075                     headerType);
2076                 break;
2077
2078         case FN_OPENWAVE_PROXY_TRUST:                   /* x-up-proxy-trust */
2079                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2080                     value_buff, valueType, valueLen, hf_wsp_header_openwave_proxy_trust,
2081                     headerType);
2082                 break;
2083
2084         case FN_OPENWAVE_PROXY_BOOKMARK:                /* x-up-proxy-bookmark */
2085                 add_openwave_string_value_header (tree, header_buff, headerLen,
2086                     value_buff, valueType, valueLen,
2087                     hf_wsp_header_openwave_proxy_bookmark, headerType);
2088                 break;
2089
2090         case FN_OPENWAVE_DEVCAP_GUI:                    /* x-up-devcap-gui */
2091                 add_openwave_integer_value_header (tree, header_buff, headerLen,
2092                     value_buff, valueType, valueLen, hf_wsp_header_openwave_devcap_gui,
2093                     headerType);
2094                 break;
2095
2096         default:
2097                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2098                     "Unsupported Openwave Header: %s",
2099                     val_to_str (headerType, vals_openwave_field_names, "Unknown (0x%02X)"));
2100                 break;
2101         }
2102         return offset;
2103 }
2104
2105 /* *********
2106 static void
2107 add_openwave_push_address_header (proto_tree *tree, tvbuff_t *header_buff,
2108     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2109     int valueLen)
2110 {
2111
2112         ???
2113         
2114 }
2115 ********* */
2116
2117 static int
2118 add_unknown_header (proto_tree *tree, tvbuff_t *tvb, int offset,
2119     guint8 headerType)
2120 {
2121         int headerStart;
2122         int valueStart;
2123         value_type_t valueType;
2124         int headerLen;
2125         guint valueLen;
2126         int valueOffset;
2127
2128         headerStart = offset;
2129
2130         /*
2131          * Skip the Short-Integer header type.
2132          */
2133         offset++;
2134
2135         valueStart = offset;
2136
2137         /*
2138          * Get the value type and length (or, if the type is VALUE_IN_LEN,
2139          * meaning the value is a Short-integer, get the value type
2140          * and the value itself).
2141          */ 
2142         valueType = get_value_type_len (tvb, valueStart, &valueLen,
2143             &valueOffset, &offset);
2144         headerLen = offset - headerStart;
2145
2146         proto_tree_add_text (tree, tvb, headerStart, headerLen,
2147                        "Unsupported Header (0x%02X)", headerType);
2148         return offset;
2149 }
2150
2151 static int
2152 add_application_header (proto_tree *tree, tvbuff_t *tvb, int offset)
2153 {
2154         int startOffset;
2155         guint tokenSize;
2156         const guint8 *token;
2157         value_type_t valueType;
2158         int subvalueLen;
2159         int subvalueOffset;
2160         guint secs;
2161         nstime_t timeValue;
2162         int asvOffset;
2163         guint stringSize;
2164
2165         startOffset = offset;
2166         tokenSize = tvb_strsize (tvb, startOffset);
2167         token = tvb_get_ptr (tvb, startOffset, tokenSize);
2168         offset += tokenSize;
2169
2170         /*
2171          * Special case header "X-WAP.TOD" that is sometimes followed
2172          * by a 4-byte date value.
2173          *
2174          * XXX - according to the 4-May-2000 WSP spec, X-Wap-Tod is
2175          * encoded as a well known header, with a code of 0x3F.
2176          */
2177         if (tokenSize == 10 && strncasecmp ("x-wap.tod", token, 9) == 0)
2178         {
2179                 valueType = get_value_type_len (tvb, offset,
2180                     &subvalueLen, &subvalueOffset, &offset);
2181                 if (get_integer (tvb, subvalueOffset, subvalueLen,
2182                     valueType, &secs) == 0)
2183                 {
2184                         /*
2185                          * Fill in the "struct timeval", and add it to the
2186                          * protocol tree.
2187                          * Note: this will succeed even if it's a Short-integer.
2188                          * A Short-integer would work, but, as the time values
2189                          * are UNIX seconds-since-the-Epoch value, and as
2190                          * there weren't WAP phones or Web servers back in
2191                          * late 1969/early 1970, they're unlikely to be used.
2192                          */
2193                         timeValue.secs = secs;
2194                         timeValue.nsecs = 0;
2195                         proto_tree_add_time (tree, hf_wsp_header_x_wap_tod,
2196                             tvb, startOffset, offset - startOffset, &timeValue);
2197                 }
2198                 else
2199                 {
2200                         proto_tree_add_text (tree, tvb, startOffset,
2201                             offset - startOffset,
2202                             "%s: invalid date value", token);
2203                 }
2204         }
2205         else
2206         {
2207                 asvOffset = offset;
2208                 stringSize = tvb_strsize (tvb, asvOffset);
2209                 offset += stringSize;
2210                 proto_tree_add_text (tree, tvb, startOffset,
2211                     offset - startOffset,
2212                     "%s: %s", token,
2213                     tvb_get_ptr (tvb, asvOffset, stringSize));
2214         }
2215         return offset;
2216 }
2217
2218 static void
2219 add_accept_header (proto_tree *tree, tvbuff_t *header_buff,
2220     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2221     int valueLen)
2222 {
2223         guint contentType;
2224         const char *contentTypeStr;
2225
2226         add_content_type_value (tree, header_buff, 0, headerLen, value_buff,
2227             valueType, valueLen, hf_wsp_header_accept,
2228             hf_wsp_header_accept_str, &contentType, &contentTypeStr);
2229 }
2230
2231 static void
2232 add_accept_xxx_header (proto_tree *tree, tvbuff_t *header_buff,
2233     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2234     int valueLen, int hf_numeric, int hf_string,
2235     const value_string *vals, const char *unknown_tag)
2236 {
2237         int offset = 0;
2238         int subvalueLen;
2239         int subvalueOffset;
2240         guint value = 0;
2241         char valString[100];
2242         const char *valMatch;
2243         guint peek;
2244         double q_value = 1.0;
2245
2246         if (valueType == VALUE_IN_LEN)
2247         {
2248                 /*
2249                  * Constrained-{charset,language} (Short-Integer).
2250                  */
2251                 proto_tree_add_uint (tree, hf_numeric,
2252                     header_buff, 0, headerLen,
2253                     valueLen);  /* valueLen is the value */
2254                 return;
2255         }
2256         if (valueType == VALUE_IS_TEXT_STRING)
2257         {
2258                 /*
2259                  * Constrained-{charset,language} (text, i.e.
2260                  * Extension-Media).
2261                  */
2262                 proto_tree_add_string (tree, hf_string,
2263                     header_buff, 0, headerLen,
2264                     tvb_get_ptr (value_buff, 0, valueLen));
2265                 return;
2266         }
2267
2268         /*
2269          * First byte had the 8th bit set.
2270          */
2271         if (valueLen == 0) {
2272                 /*
2273                  * Any-{charset,language}.
2274                  */
2275                 proto_tree_add_string (tree, hf_string,
2276                         header_buff, 0, headerLen,
2277                         "*");
2278                 return;
2279         }
2280
2281         /*
2282          * Accept-{charset,language}-general-form; Value-length, followed
2283          * by Well-known-{charset,language} or {Token-text,Text-string},
2284          * possibly followed by a Q-value.
2285          * 
2286          * Get Value-length.
2287          */
2288         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
2289             &subvalueOffset, &offset);
2290         if (valueType == VALUE_IS_TEXT_STRING)
2291         {
2292                 /*
2293                  * {Token-text,Text-string}.
2294                  */
2295                 valMatch =
2296                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen);
2297                 proto_tree_add_string (tree, hf_string,
2298                         value_buff, 0, valueLen, valMatch);
2299         } else {
2300                 /*
2301                  * Well-known-{charset,langugage}; starts with an
2302                  * Integer-value.
2303                  */
2304                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
2305                     valueType, &value) < 0)
2306                 {
2307                         valMatch = "Invalid integer";
2308                 }
2309                 else
2310                 {
2311                         valMatch = val_to_str(value, vals, unknown_tag);
2312                 }
2313         }
2314
2315         /* Any remaining data relates to Q-value */
2316         if (offset < valueLen)
2317         {
2318                 peek = tvb_get_guintvar (value_buff, offset, NULL);
2319                 if (peek <= 100) {
2320                         peek = (peek - 1) * 10;
2321                 }
2322                 else {
2323                         peek -= 100;
2324                 }
2325                 q_value = peek/1000.0;
2326         }
2327
2328         /* Build string including Q-value if present */
2329         if (q_value == 1.0)                     /* Default */
2330         {
2331                 snprintf (valString, 100, "%s", valMatch);
2332         }
2333         else
2334         {
2335                 snprintf (valString, 100, "%s; Q=%5.3f", valMatch, q_value);
2336         }
2337         /* Add string to tree */
2338         proto_tree_add_string (tree, hf_string,
2339             header_buff, 0, headerLen, valString);
2340 }
2341
2342 static void
2343 add_accept_ranges_header (proto_tree *tree, tvbuff_t *header_buff,
2344     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2345     int valueLen)
2346 {
2347         if (valueType == VALUE_IN_LEN)
2348         {
2349                 /*
2350                  * Must be 0 (None) or 1 (Bytes) (the 8th bit was stripped
2351                  * off).
2352                  */
2353                 proto_tree_add_uint (tree, hf_wsp_header_accept_ranges,
2354                     header_buff, 0, headerLen,
2355                     valueLen);  /* valueLen is the value */
2356                 return;
2357         }
2358         if (valueType == VALUE_IS_TEXT_STRING)
2359         {
2360                 /*
2361                  * Token-text.
2362                  */
2363                 proto_tree_add_string (tree, hf_wsp_header_accept_ranges_str,
2364                     header_buff, 0, headerLen,
2365                     tvb_get_ptr (value_buff, 0, valueLen));
2366                 return;
2367         }
2368
2369         /*
2370          * Not valid.
2371          */
2372         fprintf(stderr, "dissect_wsp: Accept-Ranges is neither None, Bytes, nor Token-text\n");
2373         return;
2374 }
2375
2376 static void
2377 add_cache_control_header (proto_tree *tree, tvbuff_t *header_buff,
2378     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2379     int valueLen)
2380 {
2381         int offset = 0;
2382         int subvalueLen;
2383         int subvalueOffset;
2384         guint value;
2385         proto_item *ti;
2386         proto_tree *parameter_tree;
2387         proto_tree *field_names_tree;
2388         guint delta_secs;
2389
2390         if (valueType == VALUE_IN_LEN)
2391         {
2392                 /*
2393                  * No-cache, No-store, Max-age, Max-stale, Min-fresh,
2394                  * Only-if-cached, Public, Private, No-transform,
2395                  * Must-revalidate, Proxy-revalidate, or S-maxage.
2396                  */
2397                 proto_tree_add_uint (tree, hf_wsp_header_cache_control,
2398                     header_buff, 0, headerLen,
2399                     valueLen);  /* valueLen is the value */
2400                 return;
2401         }
2402         if (valueType == VALUE_IS_TEXT_STRING)
2403         {
2404                 /*
2405                  * Cache-extension.
2406                  */
2407                 proto_tree_add_string (tree, hf_wsp_header_cache_control_str,
2408                     header_buff, 0, headerLen,
2409                     tvb_get_ptr (value_buff, 0, valueLen));
2410                 return;
2411         }
2412
2413         /*
2414          * Value-length Cache-directive.
2415          * Get first field of Cache-directive.
2416          */
2417         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2418             &subvalueOffset, &offset);
2419         if (valueType == VALUE_IS_TEXT_STRING)
2420         {
2421                 /*
2422                  * Cache-extension Parameter.
2423                  */
2424                 ti = proto_tree_add_string (tree, hf_wsp_header_cache_control_str,
2425                     header_buff, 0, headerLen,
2426                     tvb_get_ptr (value_buff, 0, valueLen));
2427                 parameter_tree = proto_item_add_subtree (ti,
2428                     ett_header_cache_control_parameters);
2429
2430                 /*
2431                  * Process the rest of the value as parameters.
2432                  */
2433                 while (tvb_reported_length_remaining (value_buff, offset) > 0) {
2434                         offset = add_parameter (parameter_tree, value_buff,
2435                             offset);
2436                 }
2437                 return;
2438         }
2439         if (get_integer (value_buff, subvalueOffset, subvalueLen, valueType,
2440             &value) < 0)
2441         {
2442                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2443                     "Invalid Cache-Control Cache-directive value");
2444         }
2445         else
2446         {
2447                 switch (value) {
2448
2449                 case NO_CACHE:
2450                 case PRIVATE:
2451                         /*
2452                          * Loop, processing Field-names.
2453                          */
2454                         ti = proto_tree_add_uint (tree,
2455                             hf_wsp_header_cache_control,
2456                             header_buff, 0, headerLen,
2457                             value);
2458                         field_names_tree = proto_item_add_subtree (ti,
2459                             ett_header_cache_control_field_names);
2460                         while (tvb_reported_length_remaining (value_buff, offset)
2461                             > 0) {
2462                                 offset = add_cache_control_field_name (tree,
2463                                     value_buff, offset, value);
2464                         }
2465                         break;
2466
2467                 case MAX_AGE:
2468                 case MAX_STALE:
2469                 case MIN_FRESH:
2470                 case S_MAXAGE:
2471                         /*
2472                          * Get Delta-second-value.
2473                          */
2474                         valueType = get_value_type_len (value_buff, offset,
2475                             &subvalueLen, &subvalueOffset, &offset);
2476                         if (get_integer (value_buff, subvalueOffset,
2477                             subvalueLen, valueType, &delta_secs) < 0)
2478                         {
2479                                 proto_tree_add_text (tree,
2480                                     header_buff, 0, headerLen,
2481                                     "Invalid Cache-Control %s Delta-second-value",
2482                                     match_strval (value, vals_cache_control));
2483                         }
2484                         else 
2485                         {
2486                                 proto_tree_add_uint_format (tree,
2487                                     hf_wsp_header_cache_control,
2488                                     header_buff, 0, headerLen,
2489                                     value,
2490                                     "Cache-Control: %s %u secs",
2491                                     match_strval (value, vals_cache_control),
2492                                     delta_secs);
2493                         }
2494                         break;
2495
2496                 default:
2497                         /*
2498                          * This should not happen, but handle it anyway.
2499                          */
2500                         proto_tree_add_uint (tree,
2501                             hf_wsp_header_cache_control,
2502                             header_buff, 0, headerLen,
2503                             value);
2504                         break;
2505                 }
2506         }
2507 }
2508
2509 static int
2510 add_cache_control_field_name (proto_tree *tree, tvbuff_t *value_buff,
2511     int offset, guint cache_control_value)
2512 {
2513         value_type_t valueType;
2514         int startOffset;
2515         int subvalueLen;
2516         int subvalueOffset;
2517
2518         startOffset = offset;
2519         valueType = get_value_type_len (value_buff, offset,
2520             &subvalueLen, &subvalueOffset, &offset);
2521         if (valueType == VALUE_IS_TEXT_STRING)
2522         {
2523                 /*
2524                  * Token-text.
2525                  */
2526                 proto_tree_add_item (tree, 
2527                     hf_wsp_header_cache_control_field_name_str,
2528                     value_buff, startOffset, offset - startOffset,
2529                     bo_little_endian);
2530         }
2531         else if (valueType == VALUE_IN_LEN)
2532         {
2533                 /*
2534                  * Short-integer Field-name.
2535                  */
2536                 proto_tree_add_uint (tree,
2537                     hf_wsp_header_cache_control_field_name,
2538                     value_buff, startOffset, offset - startOffset,
2539                     subvalueLen);
2540         }
2541         else
2542         {
2543                 /*
2544                  * Long-integer - illegal.
2545                  */
2546                 proto_tree_add_text (tree,
2547                     value_buff, startOffset, offset - startOffset,
2548                     "Invalid Cache-Control %s Field-name",
2549                     match_strval (cache_control_value, vals_cache_control));
2550         }       
2551         return offset;
2552 }
2553
2554 static void
2555 add_connection_header (proto_tree *tree, tvbuff_t *header_buff,
2556     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2557     int valueLen)
2558 {
2559         int offset = 0;
2560
2561         if (valueType == VALUE_LEN_SUPPLIED)
2562         {
2563                 /*
2564                  * Invalid.
2565                  */
2566                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2567                     "Invalid Connection value");
2568                 return;
2569         }
2570         if (valueType == VALUE_IS_TEXT_STRING)
2571         {
2572                 /*
2573                  * Token-text.
2574                  */
2575                 proto_tree_add_string (tree,
2576                     hf_wsp_header_connection_str,
2577                     header_buff, 0, headerLen,
2578                     tvb_get_ptr (value_buff, 0, valueLen));
2579                 return;
2580         }
2581
2582         /*
2583          * First byte had the 8th bit set.
2584          */
2585         if (valueLen == 0) {
2586                 /*
2587                  * Close.
2588                  */
2589                 proto_tree_add_uint (tree, hf_wsp_header_connection,
2590                     header_buff, offset, headerLen, valueLen);
2591                 return;
2592         }
2593
2594         /*
2595          * Invalid.
2596          */
2597         proto_tree_add_text (tree, header_buff, 0, headerLen,
2598             "Invalid Connection value");
2599 }
2600
2601 static void
2602 add_pragma_header (proto_tree *tree, tvbuff_t *header_buff,
2603     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2604     int valueLen)
2605 {
2606         int offset = 0;
2607         int subvalueLen;
2608         int subvalueOffset;
2609
2610         if (valueType == VALUE_IN_LEN)
2611         {
2612                 /*
2613                  * Invalid.
2614                  */
2615                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2616                     "Invalid Pragma");
2617                 return;
2618         }
2619         if (valueType == VALUE_IS_TEXT_STRING)
2620         {
2621                 /*
2622                  * Invalid?
2623                  */
2624                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2625                     "Invalid Pragma");
2626                 return;
2627         }
2628
2629         /*
2630          * First byte had the 8th bit set.
2631          */
2632         if (valueLen == 0) {
2633                 /*
2634                  * No-cache.
2635                  */
2636                 proto_tree_add_string (tree, hf_wsp_header_pragma,
2637                     header_buff, 0, headerLen, "No-cache");
2638                 return;
2639         }
2640
2641         /*
2642          * Value-length, followed by Parameter.
2643          * 
2644          * Get Value-length.
2645          */
2646         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
2647             &subvalueOffset, &offset);
2648         if (valueType == VALUE_IS_TEXT_STRING)
2649         {
2650                 /*
2651                  * Parameter - a text string.
2652                  */
2653                 proto_tree_add_string (tree, hf_wsp_header_pragma,
2654                     header_buff, 0, headerLen,
2655                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
2656         } else {
2657                 /*
2658                  * Parameter - numeric; illegal?
2659                  */
2660                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2661                     "Invalid Pragma");
2662         }
2663 }
2664
2665 static void
2666 add_transfer_encoding_header (proto_tree *tree, tvbuff_t *header_buff,
2667     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2668     int valueLen)
2669 {
2670         int offset = 0;
2671
2672         if (valueType == VALUE_LEN_SUPPLIED)
2673         {
2674                 /*
2675                  * Invalid.
2676                  */
2677                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2678                     "Invalid Transfer-Encoding value");
2679                 return;
2680         }
2681         if (valueType == VALUE_IS_TEXT_STRING)
2682         {
2683                 /*
2684                  * Token-text.
2685                  */
2686                 proto_tree_add_string (tree,
2687                     hf_wsp_header_transfer_encoding_str,
2688                     header_buff, 0, headerLen,
2689                     tvb_get_ptr (value_buff, 0, valueLen));
2690                 return;
2691         }
2692
2693         /*
2694          * First byte had the 8th bit set.
2695          */
2696         if (valueLen == 0) {
2697                 /*
2698                  * Chunked.
2699                  */
2700                 proto_tree_add_uint (tree, hf_wsp_header_transfer_encoding,
2701                     header_buff, offset, headerLen, valueLen);
2702                 return;
2703         }
2704
2705         /*
2706          * Invalid.
2707          */
2708         proto_tree_add_text (tree, header_buff, 0, headerLen,
2709             "Invalid Transfer Encoding value");
2710 }
2711
2712 static void
2713 add_warning_header (proto_tree *tree, tvbuff_t *header_buff,
2714     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2715     int valueLen)
2716 {
2717         int offset = 0;
2718         proto_item *ti;
2719         proto_tree *warning_tree;
2720         int subvalueLen;
2721         int subvalueOffset;
2722
2723         /*
2724          * Put the items under a header.
2725          * XXX - make the text of the item summarize the elements.
2726          */
2727         ti = proto_tree_add_item (tree, hf_wsp_header_warning,
2728             header_buff, 0, headerLen, bo_little_endian);
2729         warning_tree = proto_item_add_subtree(ti, ett_header_warning);
2730         
2731         if (valueType == VALUE_IN_LEN)
2732         {
2733                 /*
2734                  * Warn-code (Short-integer).
2735                  */
2736                 proto_tree_add_uint (warning_tree, hf_wsp_header_warning_code,
2737                     header_buff, 0, headerLen,
2738                     valueLen);  /* valueLen is the value */
2739                 return;
2740         }
2741         if (valueType == VALUE_IS_TEXT_STRING)
2742         {
2743                 /*
2744                  * Invalid.
2745                  */
2746                 proto_tree_add_text (warning_tree, header_buff, 0, headerLen,
2747                     "Invalid Warning (all text)");
2748                 return;
2749         }
2750
2751         /*
2752          * Warning-value; Warn-code, followed by Warn-agent, followed by
2753          * Warn-text.
2754          */
2755         /*
2756          * Get Short-integer Warn-code.
2757          */
2758         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2759             &subvalueOffset, &offset);
2760         if (valueType != VALUE_IN_LEN)
2761         {
2762                 /*
2763                  * Not a Short-integer.
2764                  */
2765                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2766                     subvalueLen, "Invalid Warn-code (not a Short-integer)");
2767                 return;
2768         }
2769         proto_tree_add_uint (warning_tree, hf_wsp_header_warning_code,
2770             value_buff, subvalueOffset, 1,
2771             subvalueLen);       /* subvalueLen is the value */
2772
2773         /*
2774          * Warn-agent; must be text.
2775          */
2776         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2777             &subvalueOffset, &offset);
2778         if (valueType != VALUE_IS_TEXT_STRING)
2779         {
2780                 /*
2781                  * Not text.
2782                  */
2783                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2784                     subvalueLen, "Invalid Warn-agent (not a text string)");
2785                 return;
2786         }
2787         proto_tree_add_item (warning_tree,
2788                 hf_wsp_header_warning_agent,
2789                 value_buff, subvalueOffset, subvalueLen, bo_little_endian);
2790
2791         /*
2792          * Warn-text; must be text.
2793          */
2794         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2795             &subvalueOffset, &offset);
2796         if (valueType != VALUE_IS_TEXT_STRING)
2797         {
2798                 /*
2799                  * Not text.
2800                  */
2801                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2802                     subvalueLen, "Invalid Warn-text (not a text string)");
2803                 return;
2804         }
2805         proto_tree_add_item (warning_tree,
2806                 hf_wsp_header_warning_text,
2807                 value_buff, subvalueOffset, subvalueLen, bo_little_endian);
2808 }
2809
2810 static void
2811 add_accept_application_header (proto_tree *tree, tvbuff_t *header_buff,
2812     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2813     int valueLen)
2814 {
2815         guint value;
2816
2817         if (valueType == VALUE_IN_LEN)
2818         {
2819                 /*
2820                  * Application-id-value; numeric, so it's App-assigned-code.
2821                  */
2822                 proto_tree_add_uint (tree, hf_wsp_header_accept_application,
2823                     header_buff, 0, headerLen,
2824                     valueLen);  /* valueLen is the value */
2825                 return;
2826         }
2827         if (valueType == VALUE_IS_TEXT_STRING)
2828         {
2829                 /*
2830                  * Uri-value.
2831                  */
2832                 proto_tree_add_string (tree, hf_wsp_header_accept_application_str,
2833                     header_buff, 0, headerLen,
2834                     tvb_get_ptr (value_buff, 0, valueLen));
2835                 return;
2836         }
2837
2838         /*
2839          * First byte had the 8th bit set.
2840          */
2841         if (valueLen == 0) {
2842                 /*
2843                  * Any-application.
2844                  */
2845                 proto_tree_add_string (tree, hf_wsp_header_accept_application_str,
2846                         header_buff, 0, headerLen,
2847                         "*");
2848                 return;
2849         }
2850
2851         /*
2852          * Integer-value, hence App-assigned-code.
2853          */
2854         if (get_integer (value_buff, 0, valueLen, valueType, &value) < 0)
2855         {
2856                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2857                         "Invalid Accept-Application App-assigned-code");
2858         }
2859         else
2860         {
2861                 proto_tree_add_uint (tree, hf_wsp_header_accept_application,
2862                     header_buff, 0, headerLen, value);
2863         }
2864 }
2865
2866 static void
2867 add_wap_application_id_header (proto_tree *tree, tvbuff_t *header_buff,
2868     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2869     int valueLen)
2870 {
2871         if (valueType == VALUE_IN_LEN)
2872         {
2873                 /*
2874                  * Must application-id (the 8th bit was stripped off).
2875                  */
2876                 proto_tree_add_uint (tree, hf_wsp_header_wap_application_id,
2877                     header_buff, 0, headerLen,
2878                     valueLen);  /* valueLen is the value */
2879                 return;
2880         }
2881         if (valueType == VALUE_IS_TEXT_STRING)
2882         {
2883                 /*
2884                  * Token-text.
2885                  */
2886                 proto_tree_add_string (tree, hf_wsp_header_wap_application_id_str,
2887                     header_buff, 0, headerLen,
2888                     tvb_get_ptr (value_buff, 0, valueLen));
2889                 return;
2890         }
2891
2892         /*
2893          * Not valid.
2894          */
2895         fprintf(stderr, "dissect_wsp: Suprising format of X-Wap-Application-Id\n");
2896         return;
2897 }
2898
2899 static void
2900 add_capabilities (proto_tree *tree, tvbuff_t *tvb, int type)
2901 {
2902         proto_item *ti;
2903         proto_tree *wsp_capabilities;
2904         guint offset = 0;
2905         guint offsetStr = 0;
2906         guint capabilitiesLen = tvb_reported_length (tvb);
2907         guint capabilitiesStart = 0;
2908         guint peek = 0;
2909         guint length = 0;
2910         guint value = 0;
2911         guint i;
2912         int ret;
2913         char valString[200];
2914
2915 #ifdef DEBUG
2916         fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, capabilitiesLen);
2917 #endif
2918
2919         /* End of buffer */
2920         if (capabilitiesLen <= 0)
2921         {
2922                 fprintf (stderr, "dissect_wsp: Capabilities = 0\n");
2923                 return;
2924         }
2925
2926 #ifdef DEBUG
2927         fprintf (stderr, "dissect_wsp: capabilities to process\n");
2928 #endif
2929
2930         ti = proto_tree_add_item (tree, hf_wsp_capabilities_section,tvb,offset,capabilitiesLen,bo_little_endian);
2931         wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
2932
2933         /* Parse Headers */
2934
2935         while (offset < capabilitiesLen)
2936         {
2937                 /* Loop round each header */
2938                 capabilitiesStart = offset;
2939                 length = tvb_get_guint8 (tvb, capabilitiesStart);
2940
2941                 if (length >= 127)              /* length */
2942                 {
2943 #ifdef DEBUG
2944                         fprintf (stderr, "dissect_wsp: capabilities length invalid %d\n",length);
2945 #endif
2946                         offset+=length;
2947                         continue;
2948                 }
2949                 offset++;
2950                 peek = tvb_get_guint8 (tvb, offset);
2951                 offset++;
2952                 switch (peek & 0x7f)
2953                 {
2954                         case 0x00 : /* Client-SDU-Size */
2955                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2956                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_client_SDU, tvb, capabilitiesStart, length+1, value);
2957                                 break;
2958                         case 0x01 : /* Server-SDU-Size */
2959                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2960                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_server_SDU, tvb, capabilitiesStart, length+1, value);
2961                                 break;
2962                         case 0x02 : /* Protocol Options */ 
2963                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2964                                 i = 0;
2965                                 valString[0]=0;
2966                                 if (value & 0x80)
2967                                 {
2968                                         ret = snprintf(valString+i,200-i,"%s","(Confirmed push facility) ");
2969                                         if (ret == -1) {
2970                                                 /*
2971                                                  * Some versions of snprintf
2972                                                  * return -1 if they'd
2973                                                  * truncate the output.
2974                                                  */
2975                                                 goto add_string;
2976                                         }
2977                                         i += ret;
2978                                 }
2979                                 if (value & 0x40)
2980                                 {
2981                                         if (i >= 200) {
2982                                                 /* No more room. */
2983                                                 goto add_string;
2984                                         }
2985                                         ret = snprintf(valString+i,200-i,"%s","(Push facility) ");
2986                                         if (ret == -1) {
2987                                                 /*
2988                                                  * Some versions of snprintf
2989                                                  * return -1 if they'd
2990                                                  * truncate the output.
2991                                                  */
2992                                                 goto add_string;
2993                                         }
2994                                         i += ret;
2995                                 }
2996                                 if (value & 0x20)
2997                                 {
2998                                         if (i >= 200) {
2999                                                 /* No more room. */
3000                                                 goto add_string;
3001                                         }
3002                                         ret = snprintf(valString+i,200-i,"%s","(Session resume facility) ");
3003                                         if (ret == -1) {
3004                                                 /*
3005                                                  * Some versions of snprintf
3006                                                  * return -1 if they'd
3007                                                  * truncate the output.
3008                                                  */
3009                                                 goto add_string;
3010                                         }
3011                                         i += ret;
3012                                 }
3013                                 if (value & 0x10)
3014                                 {
3015                                         if (i >= 200) {
3016                                                 /* No more room. */
3017                                                 goto add_string;
3018                                         }
3019                                         ret = snprintf(valString+i,200-i,"%s","(Acknowledgement headers) ");
3020                                         if (ret == -1) {
3021                                                 /*
3022                                                  * Some versions of snprintf
3023                                                  * return -1 if they'd
3024                                                  * truncate the output.
3025                                                  */
3026                                                 goto add_string;
3027                                         }
3028                                         i += ret;
3029                                 }
3030                         add_string:
3031                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_protocol_opt, tvb, capabilitiesStart, length+1, valString);
3032                                 break;
3033                         case 0x03 : /* Method-MOR */ 
3034                                 value = tvb_get_guint8(tvb, offset);
3035                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_method_MOR, tvb, capabilitiesStart, length+1, value);
3036                                 break;
3037                         case 0x04 : /* Push-MOR */ 
3038                                 value = tvb_get_guint8(tvb, offset);
3039                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_push_MOR, tvb, capabilitiesStart, length+1, value);
3040                                 break;
3041                                 break;
3042                         case 0x05 : /* Extended Methods */ 
3043                                 offsetStr = offset;
3044                                 offset++;
3045                                 add_capability_vals(tvb, (type == CONNECT),
3046                                     offsetStr, length, capabilitiesStart,
3047                                     valString, sizeof valString);
3048                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_extended_methods, tvb, capabilitiesStart, length+1, valString);
3049                                 break;
3050                         case 0x06 : /* Header Code Pages */ 
3051                                 offsetStr = offset;
3052                                 offset++;
3053                                 add_capability_vals(tvb, (type == CONNECT),
3054                                     offsetStr, length, capabilitiesStart,
3055                                     valString, sizeof valString);
3056                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_header_code_pages, tvb, capabilitiesStart, length+1, valString);
3057                                 break;
3058                         case 0x07 : /* Aliases */
3059                                 break;
3060                         default:
3061                                 proto_tree_add_text (wsp_capabilities, tvb , capabilitiesStart, length+1,
3062                                        "Unsupported Header (0x%02X)", peek & 0x7F);
3063                                 break;
3064                 }
3065                 offset=capabilitiesStart+length+1;
3066         }
3067 }
3068
3069 static void
3070 add_capability_vals(tvbuff_t *tvb, gboolean add_string, int offsetStr,
3071     guint length, guint capabilitiesStart, char *valString,
3072     size_t valStringSize)
3073 {
3074         guint i;
3075         int ret;
3076         guint value;
3077         guint8 c;
3078
3079         i = 0;
3080         while ((offsetStr-capabilitiesStart) <= length)
3081         {
3082                 value = tvb_get_guint8(tvb, offsetStr);
3083                 if (i >= valStringSize) {
3084                         /* No more room. */
3085                         break;
3086                 }
3087                 if (add_string)
3088                 {
3089                         ret = snprintf(valString+i,valStringSize-i,
3090                             "(%d - ",value);
3091                 }
3092                 else
3093                 {
3094                         ret = snprintf(valString+i,valStringSize-i,"(%d) ",
3095                             value);
3096                 }
3097                 if (ret == -1) {
3098                         /*
3099                          * Some versions of snprintf return -1
3100                          * if they'd truncate the output.
3101                          */
3102                         break;
3103                 }
3104                 i += ret;
3105                 offsetStr++;
3106                 if (add_string)
3107                 {
3108                         for (;(c = tvb_get_guint8(tvb, offsetStr))
3109                             && i < valStringSize - 1; i++,offsetStr++)
3110                                 valString[i] = c;
3111                         offsetStr++;
3112                         if (i < valStringSize - 2) {
3113                                 valString[i++] = ')';
3114                                 valString[i++] = ' ';
3115                         }
3116                 }
3117         }
3118         valString[i] = '\0';
3119 }
3120
3121 static value_type_t
3122 get_value_type_len (tvbuff_t *tvb, int offset, guint *valueLen,
3123     int *valueOffset, int *nextOffset)
3124 {
3125         guint8 peek;
3126         guint32 len;
3127         guint count;
3128
3129         /* Get value part of header */
3130         peek = tvb_get_guint8 (tvb, offset);
3131         if (peek <= 30)
3132         {
3133                 /*
3134                  * The value follows "peek", and is "peek" octets long.
3135                  */
3136 #ifdef DEBUG
3137                 fprintf (stderr, "dissect_wsp: Looking for %d octets\n", peek);
3138 #endif
3139                 len = peek;
3140                 *valueLen = len;        /* Length of value */
3141                 offset++;               /* Skip the length */
3142                 *valueOffset = offset;  /* Offset of value */
3143                 offset += len;          /* Skip the value */
3144                 *nextOffset = offset;   /* Offset after value */
3145                 return VALUE_LEN_SUPPLIED;
3146         }
3147         else if (peek == 31)
3148         {
3149                 /*
3150                  * A uintvar giving the length of the value follows
3151                  * "peek", and the value follows that.
3152                  */
3153 #ifdef DEBUG
3154                 fprintf (stderr, "dissect_wsp: Looking for uintvar octets\n");
3155 #endif
3156                 offset++;               /* Skip the uintvar indicator */
3157                 count = 0;              /* Initialise count */
3158                 len = tvb_get_guintvar (tvb, offset, &count);
3159                 *valueLen = len;        /* Length of value */
3160                 offset += count;        /* Skip the length */
3161                 *valueOffset = offset;  /* Offset of value */
3162                 offset += len;          /* Skip the value */
3163                 *nextOffset = offset;   /* Offset after value */
3164                 return VALUE_LEN_SUPPLIED;
3165         }
3166         else if (peek <= 127)
3167         {
3168                 /*
3169                  * The value is a NUL-terminated string, and "peek"
3170                  * is the first octet of the string.
3171                  */
3172 #ifdef DEBUG
3173                 fprintf (stderr, "dissect_wsp: Looking for NUL-terminated string\n");
3174 #endif
3175                 len = tvb_strsize (tvb, offset);
3176                 *valueLen = len;        /* Length of value */
3177                 *valueOffset = offset;  /* Offset of value */
3178                 offset += len;          /* Skip the value */
3179                 *nextOffset = offset;   /* Offset after value */
3180                 return VALUE_IS_TEXT_STRING;
3181         }
3182         else
3183         {
3184                 /*
3185                  * "peek", with the 8th bit stripped off, is the value.
3186                  */
3187 #ifdef DEBUG
3188                 fprintf (stderr, "dissect_wsp: Value is %d\n", (peek & 0x7F));
3189 #endif
3190                 *valueLen = peek & 0x7F; /* Return the value itself */
3191                 *valueOffset = offset;  /* Offset of value */
3192                 offset++;               /* Skip the value */
3193                 *nextOffset = offset;   /* Offset after value */
3194                 return VALUE_IN_LEN;
3195         }
3196 }
3197
3198 static guint
3199 get_uintvar (tvbuff_t *tvb, guint offset, guint offsetEnd)
3200 {
3201         guint value = 0;
3202         guint octet;
3203
3204         do
3205         {
3206                 octet = tvb_get_guint8 (tvb, offset);
3207                 offset++;
3208                 value <<= 7;
3209                 value += octet & 0x7f;
3210         }
3211         while ((offsetEnd > offset) && (octet & 0x80));
3212         return value;
3213 }
3214
3215 static void
3216 add_content_type_value (proto_tree *tree, tvbuff_t *header_buff,
3217     int headerOffset, int headerLen, tvbuff_t *value_buff,
3218     value_type_t valueType, int valueLen, int hf_numeric, int hf_string,
3219     guint *contentTypep, const char **contentTypeStrp)
3220 {
3221         proto_item *ti;
3222         proto_tree *parameter_tree;
3223         const char *contentTypeStr;
3224         int offset;
3225         int subvalueLen;
3226         int subvalueOffset;
3227         guint value;
3228
3229         if (valueType == VALUE_IN_LEN)
3230         {
3231                 /*
3232                  * Constrained-media (Short-Integer).
3233                  */
3234                 proto_tree_add_uint (tree, hf_numeric,
3235                     header_buff, headerOffset, headerLen,
3236                     valueLen);  /* valueLen is the value */
3237
3238                 /*
3239                  * Return the numerical value, and a null string value
3240                  * indicating that the value is numerical.
3241                  */
3242                 *contentTypep = valueLen;
3243                 *contentTypeStrp = NULL;
3244                 return;
3245         }
3246         if (valueType == VALUE_IS_TEXT_STRING)
3247         {
3248                 /*
3249                  * Constrained-media (text, i.e. Extension-Media).
3250                  */
3251                 contentTypeStr = tvb_get_ptr (value_buff, 0, valueLen);
3252                 proto_tree_add_string (tree, hf_string,
3253                     header_buff, headerOffset, headerLen,
3254                     contentTypeStr);
3255
3256                 /*
3257                  * Return the string value, and set the numerical value
3258                  * to 0 (as it shouldn't be used).
3259                  */
3260                 *contentTypep = 0;
3261                 *contentTypeStrp = contentTypeStr;
3262                 return;
3263         }
3264
3265         /*
3266          * Content-general-form; Value-length, followed by Media-range,
3267          * followed by optional Accept-parameters.
3268          *
3269          * Get Value-length.
3270          */
3271         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
3272             &subvalueOffset, &offset);
3273         if (valueType == VALUE_IS_TEXT_STRING)
3274         {
3275                 /*
3276                  * Extension-Media; value is a string.
3277                  */
3278                 contentTypeStr =
3279                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen);
3280                 ti = proto_tree_add_string (tree, hf_string, header_buff,
3281                     headerOffset, headerLen, contentTypeStr);
3282
3283                 /*
3284                  * Return the string value, and set the numerical value
3285                  * to 0 (as it shouldn't be used).
3286                  */
3287                 *contentTypep = 0;
3288                 *contentTypeStrp = contentTypeStr;
3289         }
3290         else
3291         {
3292                 /*
3293                  * Well-known-media; value is an Integer.
3294                  */
3295                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
3296                     valueType, &value) < 0)
3297                 {
3298                         proto_tree_add_text (tree, header_buff,
3299                             headerOffset, headerLen,
3300                             "Invalid integer for Well-known-media");
3301
3302                         /*
3303                          * Content type is invalid.
3304                          * Don't try to parse the rest of the value.
3305                          */
3306                         *contentTypep = 0;
3307                         *contentTypeStrp = NULL;
3308                         return;
3309                 }
3310                 ti = proto_tree_add_uint (tree, hf_numeric,
3311                     header_buff, headerOffset, headerLen, value);
3312
3313                 /*
3314                  * Return the numerical value, and a null string value
3315                  * indicating that the value is numerical.
3316                  */
3317                 *contentTypep = value;
3318                 *contentTypeStrp = NULL;
3319         }
3320
3321         /*
3322          * Process the rest of the value as parameters.
3323          */
3324         parameter_tree = proto_item_add_subtree(ti,
3325             ett_content_type_parameters);
3326         while (tvb_reported_length_remaining (value_buff, offset) > 0)
3327                 offset = add_parameter (parameter_tree, value_buff, offset);
3328 }
3329
3330 guint
3331 add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset,
3332     guint *contentTypep, const char **contentTypeStrp)
3333 {
3334         int valueStart;
3335         value_type_t valueType;
3336         int valueTypeLen;
3337         guint valueLen;
3338         int valueOffset;
3339         tvbuff_t *value_buff;
3340
3341         valueStart = offset;
3342
3343         /*
3344          * Get the value type and length (or, if the type is VALUE_IN_LEN,
3345          * meaning the value is a Short-integer, get the value type
3346          * and the value itself).
3347          */ 
3348         valueType = get_value_type_len (tvb, valueStart, &valueLen,
3349             &valueOffset, &offset);
3350         valueTypeLen = offset - valueStart;
3351
3352         /*
3353          * Get a tvbuff for the value.
3354          * XXX - can valueLen be 0?
3355          * XXX - cut the actual length short so that it doesn't run
3356          * past the actual length of tvb.
3357          */
3358         if (valueType != VALUE_IN_LEN) {
3359                 value_buff = tvb_new_subset (tvb, valueOffset, valueLen,
3360                     valueLen);
3361         } else {
3362                 /*
3363                  * XXX - when the last dissector is tvbuffified,
3364                  * so that NULL is no longer a valid tvb pointer
3365                  * value in "proto_tree_add" calls, just
3366                  * set "value_buff" to NULL.
3367                  *
3368                  * XXX - can we already do that?  I.e., will that
3369                  * cause us always to crash if we mistakenly try
3370                  * to fetch the value of a VALUE_IN_LEN item?
3371                  */
3372                 value_buff = tvb_new_subset (tvb, valueStart, 0, 0);
3373         }
3374
3375         add_content_type_value (tree, tvb, valueStart, valueTypeLen, value_buff,
3376             valueType, valueLen, hf_wsp_content_type,
3377             hf_wsp_content_type_str, contentTypep, contentTypeStrp);
3378
3379         return offset;
3380 }
3381
3382 static void
3383 add_integer_value_header (proto_tree *tree, tvbuff_t *header_buff,
3384     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
3385     int valueLen, int hf_numeric, guint8 headerType)
3386 {
3387         add_integer_value_header_common (tree, header_buff, headerLen,
3388             value_buff, valueType, valueLen, hf_numeric, headerType,
3389             vals_field_names);
3390 }
3391
3392 static void
3393 add_openwave_integer_value_header (proto_tree *tree, tvbuff_t *header_buff,
3394     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
3395     int valueLen, int hf_numeric, guint8 headerType)
3396 {
3397         add_integer_value_header_common (tree, header_buff, headerLen,
3398             value_buff, valueType, valueLen, hf_numeric, headerType,
3399             vals_openwave_field_names);
3400 }
3401
3402 static void
3403 add_integer_value_header_common (proto_tree *tree, tvbuff_t *header_buff,
3404     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
3405     int valueLen, int hf_numeric, guint8 headerType,
3406     const value_string *vals)
3407 {
3408         guint value;
3409
3410         if (get_integer (value_buff, 0, valueLen, valueType, &value) < 0)
3411         {
3412                 proto_tree_add_text (tree, header_buff, 0, headerLen,
3413                     "Invalid %s integer value",
3414                     match_strval (headerType, vals));
3415         }
3416         else
3417         {
3418                 proto_tree_add_uint (tree, hf_numeric,
3419                     header_buff, 0, headerLen, value);
3420         }
3421 }
3422
3423 static void
3424 add_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
3425     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
3426     int valueLen, int hf_string, guint8 headerType)
3427 {
3428         add_string_value_header_common (tree, header_buff, headerLen,
3429             value_buff, valueType, valueLen, hf_string, headerType,
3430             vals_field_names);
3431 }
3432
3433 static void
3434 add_openwave_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
3435     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
3436     int valueLen, int hf_string, guint8 headerType)
3437 {
3438         add_string_value_header_common (tree, header_buff, headerLen,
3439             value_buff, valueType, valueLen, hf_string, headerType,
3440             vals_openwave_field_names);
3441 }
3442
3443 static void
3444 add_string_value_header_common (proto_tree *tree, tvbuff_t *header_buff,
3445     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
3446     int valueLen, int hf_string, guint8 headerType,
3447     const value_string *vals)
3448 {
3449         if (valueType != VALUE_IS_TEXT_STRING)
3450         {
3451                 proto_tree_add_text (tree, header_buff, 0, headerLen,
3452                     "Invalid %s string value",
3453                     match_strval (headerType, vals));
3454         }
3455         else
3456         {
3457                 proto_tree_add_string (tree, hf_string, header_buff,
3458                         0, headerLen, tvb_get_ptr (value_buff, 0, valueLen));
3459         }
3460 }
3461
3462 static void
3463 add_quoted_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
3464     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
3465     int valueLen, int hf_string, guint8 headerType)
3466 {
3467         if (valueType != VALUE_IS_TEXT_STRING)
3468         {
3469                 proto_tree_add_text (tree, header_buff, 0, headerLen,
3470                     "Invalid %s quoted string value",
3471                     match_strval (headerType, vals_field_names));
3472         }
3473         else
3474         {
3475                 proto_tree_add_string (tree, hf_string, header_buff,
3476                         0, headerLen, tvb_get_ptr (value_buff, 1, valueLen - 1));
3477         }
3478 }
3479
3480 /* Utility function to add a date value to the protocol tree */
3481 static void
3482 add_date_value_header (proto_tree *tree, tvbuff_t *header_buff,
3483     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
3484     int valueLen, int hf_time, guint8 headerType)
3485 {
3486         guint secs;
3487         nstime_t timeValue;
3488
3489         /* Attempt to get the date value from the buffer */
3490         if (get_integer (value_buff, 0, valueLen, valueType, &secs) == 0)
3491         {
3492                 /*
3493                  * Fill in the "struct timeval", and add it to the
3494                  * protocol tree.
3495                  * Note: this will succeed even if it's a Short-integer.
3496                  * A Short-integer would work, but, as the time values
3497                  * are UNIX seconds-since-the-Epoch value, and as
3498                  * there weren't WAP phones or Web servers back in
3499                  * late 1969/early 1970, they're unlikely to be used.
3500                  */
3501                 timeValue.secs = secs;
3502                 timeValue.nsecs = 0;
3503                 proto_tree_add_time (tree, hf_time, header_buff, 0,
3504                         headerLen, &timeValue);
3505         }
3506         else
3507         {
3508                 proto_tree_add_text (tree, header_buff, 0, headerLen,
3509                     "Invalid %s date value",
3510                     match_strval (headerType, vals_field_names));
3511         }
3512 }
3513
3514 static int
3515 add_parameter (proto_tree *tree, tvbuff_t *value_buff, int offset)
3516 {
3517         int startOffset;
3518         value_type_t valueType;
3519         int subvalueLen;
3520         int subvalueOffset;
3521         guint value;
3522
3523         startOffset = offset;
3524         valueType = get_value_type_len (value_buff, offset,
3525             &subvalueLen, &subvalueOffset, &offset);
3526         if (valueType == VALUE_IS_TEXT_STRING)
3527         {
3528                 /*
3529                  * Untyped-parameter.
3530                  */
3531                 offset = add_untyped_parameter (tree, value_buff, startOffset, offset);
3532                 return offset;
3533         }
3534
3535         /*
3536          * Well-known-parameter-token.
3537          */
3538         if (get_integer (value_buff, subvalueOffset,
3539             subvalueLen, valueType, &value) < 0)
3540         {
3541                 proto_tree_add_text (tree, value_buff, startOffset,
3542                     offset - startOffset,
3543                     "Invalid Well-known-parameter-token");
3544                 return offset;
3545         }
3546
3547         switch (value) {
3548
3549         case 0x01:      /* Charset */
3550                 offset = add_parameter_charset (tree, value_buff, startOffset, offset);
3551                 break;
3552
3553         case 0x03:      /* Type */
3554                 offset = add_parameter_type (tree, value_buff, startOffset, offset);
3555                 break;
3556
3557         case 0x05:      /* Name */
3558                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3559                                     hf_wsp_parameter_name, "Name");
3560                 break;
3561
3562         case 0x06:      /* Filename */
3563                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3564                                     hf_wsp_parameter_filename, "Filename");
3565                 break;
3566
3567         case 0x09:      /* Type (special) */
3568                 offset = add_constrained_encoding(tree, value_buff, startOffset, offset);
3569                 break;
3570
3571         case 0x0A:      /* Start */
3572                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3573                                     hf_wsp_parameter_start, "Start");
3574                 break;
3575
3576         case 0x0B:      /* Start-info */
3577                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3578                                     hf_wsp_parameter_start_info, "Start-info");
3579                 break;
3580
3581         case 0x0C:      /* Comment */
3582                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3583                                     hf_wsp_parameter_comment, "Comment");
3584                 break;
3585
3586         case 0x0D:      /* Domain */
3587                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3588                                     hf_wsp_parameter_domain, "Domain");
3589                 break;
3590
3591         case 0x0F:      /* Path */
3592                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3593                                     hf_wsp_parameter_path, "Path");
3594                 break;
3595
3596         case 0x00:      /* Q */
3597         case 0x02:      /* Level */
3598         case 0x07:      /* Differences */
3599         case 0x08:      /* Padding */
3600         case 0x0E:      /* Max-Age */
3601         case 0x10:      /* Secure */
3602         default:
3603                 break;
3604         }
3605
3606         return offset;
3607 }
3608
3609 static int
3610 add_untyped_parameter (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3611     int offset)
3612 {
3613         const guint8 *token;
3614         value_type_t valueType;
3615         int subvalueLen;
3616         int subvalueOffset;
3617         guint value;
3618         int vOffset = offset;
3619
3620         token = tvb_get_ptr (value_buff, startOffset, offset - startOffset);
3621         /*
3622          * Now an Untyped-value; either an Integer-value or a Text-value.
3623          */
3624         valueType = get_value_type_len (value_buff, offset,
3625             &subvalueLen, &subvalueOffset, &offset);
3626         if (valueType == VALUE_IS_TEXT_STRING)
3627         {
3628                 /*
3629                  * Text-value.
3630                  */
3631                 if ((offset - vOffset) == 1) {
3632                         /*
3633                          * No-value.  (stringSize includes the terminating
3634                          * null byte, so an empty string has a size of 1.)
3635                          */
3636                         proto_tree_add_text (tree, value_buff, startOffset,
3637                             offset - startOffset,
3638                             "%s", token);
3639                         return offset;
3640                 }
3641                 proto_tree_add_text (tree, value_buff, startOffset,
3642                     offset - startOffset,
3643                     "%s: %s", token,
3644                     tvb_get_ptr (value_buff, vOffset, offset - vOffset));
3645         }
3646         else
3647         {
3648                 /*
3649                  * Integer-value.
3650                  */
3651                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
3652                     valueType, &value) == 0)
3653                 {
3654                         proto_tree_add_text (tree, value_buff, startOffset,
3655                             offset - startOffset,
3656                             "%s: %u", token, value);
3657                 }
3658                 else
3659                 {
3660                         proto_tree_add_text (tree, value_buff, startOffset,
3661                             offset - startOffset,
3662                             "%s: Invalid Integer-value", token);
3663                 }
3664         }
3665         return offset;
3666 }
3667
3668 static int
3669 add_parameter_charset (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3670     int offset)
3671 {
3672         value_type_t valueType;
3673         int subvalueLen;
3674         int subvalueOffset;
3675         guint value;
3676
3677         valueType = get_value_type_len (value_buff, offset,
3678             &subvalueLen, &subvalueOffset, &offset);
3679         if (valueType == VALUE_IN_LEN)
3680         {
3681                 /*
3682                  * Integer-value.
3683                  */
3684                 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset,
3685                     value_buff, startOffset, offset - startOffset,
3686                     subvalueLen);       /* subvalueLen is the value */
3687                 return offset;
3688         }
3689         if (valueType == VALUE_IS_TEXT_STRING)
3690         {
3691                 /*
3692                  * Invalid.
3693                  */
3694                 proto_tree_add_text (tree, value_buff, startOffset,
3695                     offset - startOffset, "Invalid Well-known charset");
3696                 return offset;
3697         }
3698
3699         /*
3700          * First byte had the 8th bit set.
3701          */
3702         if (subvalueLen == 0) {
3703                 /*
3704                  * Any-charset.
3705                  * XXX - add this as a field?
3706                  */
3707                 proto_tree_add_text (tree, value_buff, startOffset,
3708                     offset- startOffset, "*");
3709                 return offset;
3710         }
3711
3712         if (get_integer(value_buff, subvalueOffset, subvalueLen,
3713             valueType, &value) == -1) {
3714                 proto_tree_add_text (tree, value_buff, startOffset,
3715                     offset - startOffset, "Length %u not handled in Well-known charset",
3716                         subvalueLen);
3717         } else {
3718                 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset,
3719                     value_buff, startOffset, offset - startOffset, value);
3720         }
3721         return offset;
3722 }
3723
3724 static int
3725 add_constrained_encoding (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3726     int offset)
3727 {
3728         value_type_t valueType;
3729         int subvalueLen;
3730         int subvalueOffset;
3731         guint value;
3732
3733         valueType = get_value_type_len (value_buff, offset,
3734             &subvalueLen, &subvalueOffset, &offset);
3735         if (valueType == VALUE_IN_LEN)
3736         {
3737                 /*
3738                  * Integer-value, invalid
3739                  */
3740                 proto_tree_add_text (tree, value_buff, startOffset,
3741                     offset - startOffset, "Invalid multipart type parameter");
3742                 return offset;
3743         }
3744         if (valueType == VALUE_IS_TEXT_STRING)
3745         {
3746                 /*
3747                  * type-label.
3748                  */
3749                 proto_tree_add_string (tree, hf_wsp_parameter_upart_type,
3750                     value_buff, startOffset, offset - startOffset,
3751                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
3752                 return offset;
3753         }
3754         /*
3755          * First byte had the 8th bit set.
3756          */
3757         get_integer(value_buff, subvalueOffset, subvalueLen, valueType, &value);
3758         proto_tree_add_uint (tree, hf_wsp_parameter_upart_type_value,
3759             value_buff, startOffset, offset - startOffset, value);
3760         return offset;
3761 }
3762
3763 static int
3764 add_parameter_type (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3765     int offset)
3766 {
3767         value_type_t valueType;
3768         int subvalueLen;
3769         int subvalueOffset;
3770         guint value;
3771
3772         valueType = get_value_type_len (value_buff, offset,
3773             &subvalueLen, &subvalueOffset, &offset);
3774         if (get_integer(value_buff, subvalueOffset, subvalueLen,
3775             valueType, &value) == -1) {
3776                 proto_tree_add_text (tree, value_buff, startOffset,
3777                     offset - startOffset, "Invalid type");
3778         } else {
3779                 proto_tree_add_uint (tree, hf_wsp_parameter_type, value_buff,
3780                     startOffset, offset - startOffset, value);
3781         }
3782         return offset;
3783 }
3784
3785 static int
3786 add_parameter_text (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3787     int offset, int hf_string, const char *paramName)
3788 {
3789         value_type_t valueType;
3790         int subvalueLen;
3791         int subvalueOffset;
3792
3793         valueType = get_value_type_len (value_buff, offset,
3794             &subvalueLen, &subvalueOffset, &offset);
3795         if (valueType != VALUE_IS_TEXT_STRING) {
3796                 proto_tree_add_text (tree, value_buff, startOffset,
3797                     offset - startOffset, "Invalid %s", paramName);
3798         } else {
3799                 proto_tree_add_string (tree, hf_string, value_buff,
3800                             startOffset, offset - startOffset,
3801                             tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
3802         }
3803         return offset;
3804 }
3805
3806 static void
3807 add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType,
3808     const char *contentTypeStr)
3809 {
3810         guint offset = 0;
3811         guint variableStart = 0;
3812         guint variableEnd = 0;
3813         guint valueStart = 0;
3814         guint valueEnd = 0;
3815         guint8 peek = 0;
3816         proto_item *ti;
3817         
3818         /* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,-1,bo_little_endian); */
3819         ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,-1,bo_little_endian);
3820
3821         if (contentTypeStr == NULL && contentType == 0x12)
3822         {
3823                 /*
3824                  * URL Encoded data.
3825                  * Iterate through post data.
3826                  */
3827                 for (offset = 0; offset < tvb_reported_length (tvb); offset++)
3828                 {
3829                         peek = tvb_get_guint8 (tvb, offset);
3830                         if (peek == '=')
3831                         {
3832                                 variableEnd = offset;
3833                                 valueStart = offset+1;
3834                         }
3835                         else if (peek == '&')
3836                         {
3837                                 if (variableEnd > 0)
3838                                 {
3839                                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
3840                                 }
3841                                 variableStart = offset+1;
3842                                 variableEnd = 0;
3843                                 valueStart = 0;
3844                                 valueEnd = 0;
3845                         }
3846                 }
3847
3848                 /* See if there's outstanding data */
3849                 if (variableEnd > 0)
3850                 {
3851                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
3852                 }
3853         }
3854         else if ((contentType == 0x22) || (contentType == 0x23) || (contentType == 0x23) || (contentType == 0x24) ||
3855                  (contentType == 0x25) || (contentType == 0x26) || (contentType == 0x33))
3856         {
3857                 add_multipart_data(ti, tvb);
3858         }
3859 }
3860
3861 static void
3862 add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
3863 {
3864         int variableLength = variableEnd-variableStart;
3865         int valueLength = 0;
3866         char *variableBuffer;
3867         char *valueBuffer;
3868
3869         variableBuffer = g_malloc (variableLength+1);
3870         strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength);
3871         variableBuffer[variableLength] = 0;
3872
3873         if (valueEnd < valueStart)
3874         {
3875                 valueBuffer = g_malloc (1);
3876                 valueBuffer[0] = 0;
3877                 valueEnd = valueStart;
3878         }
3879         else
3880         {
3881                 valueLength = valueEnd-valueStart;
3882                 valueBuffer = g_malloc (valueLength+1);
3883                 strncpy (valueBuffer, tvb_get_ptr (tvb, valueStart, valueLength), valueLength);
3884                 valueBuffer[valueLength] = 0;
3885         }
3886
3887         /* Check for variables with no value */
3888         if (valueStart >= tvb_reported_length (tvb))
3889         {
3890                 valueStart = tvb_reported_length (tvb);
3891                 valueEnd = valueStart;
3892         }
3893         valueLength = valueEnd-valueStart;
3894
3895         proto_tree_add_text (tree, tvb, variableStart, valueEnd-variableStart, "%s: %s", variableBuffer, valueBuffer);
3896
3897         g_free (variableBuffer);
3898         g_free (valueBuffer);
3899 }
3900
3901 void
3902 add_multipart_data (proto_tree *tree, tvbuff_t *tvb)
3903 {
3904         int              offset = 0;
3905         guint            nextOffset;
3906         guint            nEntries = 0;
3907         guint            count;
3908         guint            HeadersLen;
3909         guint            DataLen;
3910         guint            contentType = 0;
3911         const char      *contentTypeStr;
3912         tvbuff_t        *tmp_tvb;
3913         int              partnr = 1;
3914         int              part_start;
3915
3916         proto_item      *sub_tree = NULL,
3917                         *ti;
3918         proto_tree      *mpart_tree;
3919
3920         nEntries = tvb_get_guintvar (tvb, offset, &count);
3921         offset += count;
3922         if (nEntries)
3923         {
3924                 sub_tree = proto_tree_add_text(tree, tvb, offset - count, 0,
3925                                         "Multipart body");
3926                 proto_item_add_subtree(sub_tree, ett_mpartlist);
3927         }
3928         while (nEntries--)
3929         {
3930                 part_start = offset;
3931                 HeadersLen = tvb_get_guintvar (tvb, offset, &count);
3932                 offset += count;
3933                 DataLen = tvb_get_guintvar (tvb, offset, &count);
3934                 offset += count;
3935                 ti = proto_tree_add_uint(sub_tree, hf_wsp_mpart, tvb, part_start,
3936                                         HeadersLen + DataLen + (offset - part_start), partnr);
3937                 mpart_tree = proto_item_add_subtree(ti, ett_multiparts);
3938                 nextOffset = add_content_type (mpart_tree, tvb, offset, &contentType, &contentTypeStr);
3939                 HeadersLen -= (nextOffset - offset);
3940                 if (HeadersLen > 0)
3941                 {
3942                         tmp_tvb = tvb_new_subset (tvb, nextOffset, HeadersLen, HeadersLen);
3943                         add_headers (mpart_tree, tmp_tvb);
3944                 }
3945                 offset = nextOffset + HeadersLen;
3946                 proto_tree_add_item (mpart_tree, hf_wsp_multipart_data, tvb, offset, DataLen, bo_little_endian);
3947                 offset += DataLen;
3948                 partnr++;
3949         }
3950 }
3951
3952 static gint
3953 get_integer (tvbuff_t *tvb, guint offset, guint valueLength,
3954     value_type_t valueType, guint *value)
3955 {
3956         if (valueType == VALUE_IS_TEXT_STRING) {
3957                 /*
3958                  * Not valid.
3959                  */
3960                 return -1;
3961         }
3962
3963         if (valueType == VALUE_IN_LEN) {
3964                 /*
3965                  * Short-integer.
3966                  */
3967                 *value = valueLength;
3968                 return 0;
3969         }
3970
3971         /*
3972          * Long-integer.
3973          */
3974         switch (valueLength)
3975         {
3976                 case 1:
3977                         *value = tvb_get_guint8(tvb, offset);
3978                         break;
3979                 case 2:
3980                         *value = tvb_get_ntohs(tvb, offset);
3981                         break;
3982                 case 3:
3983                         *value = tvb_get_ntoh24(tvb, offset);
3984                         break;
3985                 case 4:
3986                         *value = tvb_get_ntohl(tvb, offset);
3987                         break;
3988                 default:
3989                         /* TODO: Need to read peek octets */
3990                         *value = 0;
3991                         fprintf (stderr, "dissect_wsp: get_integer size %u NYI\n", valueLength);
3992                         break;
3993         }
3994         return 0;
3995 }
3996
3997 /* Register the protocol with Ethereal */
3998 void
3999 proto_register_wsp(void)
4000 {                 
4001
4002 /* Setup list of header fields */
4003         static hf_register_info hf[] = {
4004                 { &hf_wsp_header_tid,
4005                         {       "Transmission ID",           
4006                                 "wsp.TID",
4007                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4008                                 "Transmission ID", HFILL
4009                         }
4010                 },
4011                 { &hf_wsp_header_pdu_type,
4012                         {       "PDU Type",           
4013                                 "wsp.pdu_type",
4014                                  FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
4015                                 "PDU Type", HFILL
4016                         }
4017                 },
4018                 { &hf_wsp_version_major,
4019                         {       "Version (Major)",           
4020                                 "wsp.version.major",
4021                                  FT_UINT8, BASE_DEC, NULL, 0xF0,
4022                                 "Version (Major)", HFILL
4023                         }
4024                 },
4025                 { &hf_wsp_version_minor,
4026                         {       "Version (Minor)",           
4027                                 "wsp.version.minor",
4028                                  FT_UINT8, BASE_DEC, NULL, 0x0F,
4029                                 "Version (Minor)", HFILL
4030                         }
4031                 },
4032                 { &hf_wsp_capability_length,
4033                         {       "Capability Length",           
4034                                 "wsp.capability.length",
4035                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4036                                 "Capability Length", HFILL
4037                         }
4038                 },
4039                 { &hf_wsp_header_length,
4040                         {       "Headers Length",           
4041                                 "wsp.headers_length",
4042                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4043                                 "Headers Length", HFILL
4044                         }
4045                 },
4046                 { &hf_wsp_capabilities_section,
4047                         {       "Capabilities",           
4048                                 "wsp.capabilities",
4049                                  FT_NONE, BASE_DEC, NULL, 0x00,
4050                                 "Capabilities", HFILL
4051                         }
4052                 },
4053                 { &hf_wsp_headers_section,
4054                         {       "Headers",           
4055                                 "wsp.headers",
4056                                  FT_NONE, BASE_DEC, NULL, 0x00,
4057                                 "Headers", HFILL
4058                         }
4059                 },
4060                 { &hf_wsp_header,
4061                         {       "Header",           
4062                                 "wsp.headers.header",
4063                                  FT_NONE, BASE_DEC, NULL, 0x00,
4064                                 "Header", HFILL
4065                         }
4066                 },
4067                 { &hf_wsp_header_uri_len,
4068                         {       "URI Length",           
4069                                 "wsp.uri_length",
4070                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4071                                 "URI Length", HFILL
4072                         }
4073                 },
4074                 { &hf_wsp_header_uri,
4075                         {       "URI",           
4076                                 "wsp.uri",
4077                                  FT_STRING, BASE_NONE, NULL, 0x00,
4078                                 "URI", HFILL
4079                         }
4080                 },
4081                 { &hf_wsp_server_session_id,
4082                         {       "Server Session ID",           
4083                                 "wsp.server.session_id",
4084                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4085                                 "Server Session ID", HFILL
4086                         }
4087                 },
4088                 { &hf_wsp_header_status,
4089                         {       "Status",           
4090                                 "wsp.reply.status",
4091                                  FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
4092                                 "Status", HFILL
4093                         }
4094                 },
4095                 { &hf_wsp_content_type,
4096                         {       "Content Type",           
4097                                 "wsp.content_type.type",
4098                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
4099                                 "Content Type", HFILL
4100                         }
4101                 },
4102                 { &hf_wsp_content_type_str,
4103                         {       "Content Type",           
4104                                 "wsp.content_type.type.string",
4105                                  FT_STRING, BASE_NONE, NULL, 0x00,
4106                                 "Content Type", HFILL
4107                         }
4108                 },
4109                 { &hf_wsp_parameter_well_known_charset,
4110                         {       "Charset",           
4111                                 "wsp.content_type.parameter.charset",
4112                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
4113                                 "Charset", HFILL
4114                         }
4115                 },
4116                 { &hf_wsp_parameter_type,
4117                         {       "Type",           
4118                                 "wsp.content_type.parameter.type",
4119                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4120                                 "Type", HFILL
4121                         }
4122                 },
4123                 { &hf_wsp_parameter_name,
4124                         {       "Name",
4125                                 "wsp.content_type.parameter.name",
4126                                  FT_STRING, BASE_NONE, NULL, 0x00,
4127                                 "Name", HFILL
4128                         }
4129                 },
4130                 { &hf_wsp_parameter_filename,
4131                         {       "Filename",
4132                                 "wsp.content_type.parameter.filename",
4133                                  FT_STRING, BASE_NONE, NULL, 0x00,
4134                                 "Filename", HFILL
4135                         }
4136                 },
4137                 { &hf_wsp_parameter_start,
4138                         {       "Start",
4139                                 "wsp.content_type.parameter.start",
4140                                  FT_STRING, BASE_NONE, NULL, 0x00,
4141                                 "Start", HFILL
4142                         }
4143                 },
4144                 { &hf_wsp_parameter_start_info,
4145                         {       "Start-info",
4146                                 "wsp.content_type.parameter.start_info",
4147                                  FT_STRING, BASE_NONE, NULL, 0x00,
4148                                 "Start-info", HFILL
4149                         }
4150                 },
4151                 { &hf_wsp_parameter_comment,
4152                         {       "Comment",
4153                                 "wsp.content_type.parameter.comment",
4154                                  FT_STRING, BASE_NONE, NULL, 0x00,
4155                                 "Comment", HFILL
4156                         }
4157                 },
4158                 { &hf_wsp_parameter_domain,
4159                         {       "Domain",
4160                                 "wsp.content_type.parameter.domain",
4161                                  FT_STRING, BASE_NONE, NULL, 0x00,
4162                                 "Domain", HFILL
4163                         }
4164                 },
4165                 { &hf_wsp_parameter_path,
4166                         {       "Path",
4167                                 "wsp.content_type.parameter.path",
4168                                  FT_STRING, BASE_NONE, NULL, 0x00,
4169                                 "Path", HFILL
4170                         }
4171                 },
4172                 { &hf_wsp_parameter_upart_type,
4173                         {       "Type",
4174                                 "wsp.content_type.parameter.upart.type",
4175                                  FT_STRING, BASE_NONE, NULL, 0x00,
4176                                 "Multipart type", HFILL
4177                         }
4178                 },
4179                 { &hf_wsp_parameter_upart_type_value,
4180                         {       "Type",
4181                                 "wsp.content_type.parameter.upart.type.int",
4182                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4183                                 "Multipart type (int value)", HFILL
4184                         }
4185                 },
4186                 { &hf_wsp_reply_data,
4187                         {       "Data",           
4188                                 "wsp.reply.data",
4189                                  FT_NONE, BASE_NONE, NULL, 0x00,
4190                                 "Data", HFILL
4191                         }
4192                 },
4193                 { &hf_wsp_header_shift_code,
4194                         {       "Shift code",           
4195                                 "wsp.header.shift",
4196                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
4197                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4198                                 "Shift code", HFILL
4199                         }
4200                 },
4201                 { &hf_wsp_header_accept,
4202                         {       "Accept",           
4203                                 "wsp.header.accept",
4204                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
4205                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
4206                                 "Accept", HFILL
4207                         }
4208                 },
4209                 { &hf_wsp_header_accept_str,
4210                         {       "Accept",           
4211                                 "wsp.header.accept.string",
4212                                  FT_STRING, BASE_NONE, NULL, 0x00,
4213                                 "Accept", HFILL
4214                         }
4215                 },
4216                 { &hf_wsp_header_accept_application,
4217                         {       "Accept-Application",           
4218                                 "wsp.header.accept_application",
4219                                  FT_UINT32, BASE_HEX, NULL, 0x00,
4220                                 "Accept-Application", HFILL
4221                         }
4222                 },
4223                 { &hf_wsp_header_accept_application_str,
4224                         {       "Accept-Application",
4225                                 "wsp.header.accept_application.string",
4226                                  FT_STRING, BASE_NONE, NULL, 0x00,
4227                                 "Accept-Application", HFILL
4228                         }
4229                 },
4230                 { &hf_wsp_header_accept_charset,
4231                         {       "Accept-Charset",           
4232                                 "wsp.header.accept_charset",
4233                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
4234                                 "Accept-Charset", HFILL
4235                         }
4236                 },
4237                 { &hf_wsp_header_accept_charset_str,
4238                         {       "Accept-Charset",           
4239                                 "wsp.header.accept_charset.string",
4240                                  FT_STRING, BASE_NONE, NULL, 0x00,
4241                                 "Accept-Charset", HFILL
4242                         }
4243                 },
4244                 { &hf_wsp_header_accept_language,
4245                         {       "Accept-Language",           
4246                                 "wsp.header.accept_language",
4247                                  FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
4248                                 "Accept-Language", HFILL
4249                         }
4250                 },
4251                 { &hf_wsp_header_accept_language_str,
4252                         {       "Accept-Language",           
4253                                 "wsp.header.accept_language.string",
4254                                  FT_STRING, BASE_NONE, NULL, 0x00,
4255                                 "Accept-Language", HFILL
4256                         }
4257                 },
4258                 { &hf_wsp_header_accept_ranges,
4259                         {       "Accept-Ranges",           
4260                                 "wsp.header.accept_ranges",
4261                                  FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
4262                                 "Accept-Ranges", HFILL
4263                         }
4264                 },
4265                 { &hf_wsp_header_accept_ranges_str,
4266                         {       "Accept-Ranges",           
4267                                 "wsp.header.accept_ranges.string",
4268                                  FT_STRING, BASE_NONE, NULL, 0x00,
4269                                 "Accept-Ranges", HFILL
4270                         }
4271                 },
4272                 { &hf_wsp_header_age,
4273                         {       "Age",           
4274                                 "wsp.header.age",
4275                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4276                                 "Age", HFILL
4277                         }
4278                 },
4279                 { &hf_wsp_header_openwave_proxy_push_addr,
4280                         {       "x-up-proxy-push-addr",
4281                                 "wsp.header.x-up-proxy-push-addr",
4282                                  FT_BYTES, BASE_HEX, NULL, 0x00,
4283                                 "The network address and port number that the handset can receive UPNOTIFY pushes on.", HFILL
4284                         }
4285                 },
4286                 { &hf_wsp_header_openwave_proxy_push_accept,
4287                         {       "x-up-proxy-push-accept",
4288                                 "wsp.header.x-up-proxy-push-accept",
4289                                  FT_STRING, BASE_NONE, NULL, 0x00,
4290                                 "The content types that the handset can handle when sent via UPNOTIFY pushes.", HFILL
4291                         }
4292                 },
4293                 { &hf_wsp_header_openwave_proxy_push_seq,
4294                         {       "x-up-proxy-push-seq",
4295                                 "wsp.header.x-up-proxy-push-seq",
4296                                  FT_UINT16, BASE_DEC, NULL, 0x00,
4297                                 "Specifies the sequence number of the last UPNOTIFY push sent.", HFILL
4298                         }
4299                 },
4300                 { &hf_wsp_header_openwave_proxy_notify,
4301                         {       "x-up-proxy-notify",           
4302                                 "wsp.header.x-up-proxy-notify",
4303                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4304                                 "Indicates to the handset that there are pending UPNOTIFY pushes waiting.", HFILL
4305                         }
4306                 },
4307                 { &hf_wsp_header_openwave_proxy_operator_domain,
4308                         {       "x-up-proxy-operator-domain",           
4309                                 "wsp.header.x-up-proxy-operator-domain",
4310                                  FT_STRING, BASE_NONE, NULL, 0x00,
4311                                 "Indicates the Trusted Provisioning Domain.", HFILL
4312                         }
4313                 },
4314                 { &hf_wsp_header_openwave_proxy_home_page,
4315                         {       "x-up-proxy-home-page",           
4316                                 "wsp.header.x-up-proxy-home-page",
4317                                  FT_STRING, BASE_NONE, NULL, 0x00,
4318                                 "Specifies the server-assigned home page URL.", HFILL
4319                         }
4320                 },
4321                 { &hf_wsp_header_openwave_devcap_has_color,
4322                         {       "x-up-devcap-has-color",           
4323                                 "wsp.header.x-up-devcap-has-color",
4324                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4325                                 "Indicates if the handset supports colour.", HFILL
4326                         }
4327                 },
4328                 { &hf_wsp_header_openwave_devcap_num_softkeys,
4329                         {       "x-up-devcap-num-softkeys",
4330                                 "wsp.header.x-up-devcap-num-softkeys",
4331                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4332                                 "The number of softkeys that can be displayed on the handset.", HFILL
4333                         }
4334                 },
4335                 { &hf_wsp_header_openwave_devcap_softkey_size,
4336                         {       "x-up-devcap-softkey-size",
4337                                 "wsp.header.x-up-devcap-softkey-size",
4338                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4339                                 "The number of chars that can be displayed on a softkey label.", HFILL
4340                         }
4341                 },
4342                 { &hf_wsp_header_openwave_devcap_screen_chars,
4343                         {       "x-up-devcap-screen-chars",
4344                                 "wsp.header.x-up-devcap-screen-chars",
4345                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4346                                 "The height and width of the handset's display in characters.", HFILL
4347                         }
4348                 },
4349                 { &hf_wsp_header_openwave_devcap_screen_pixels,
4350                         {       "x-up-devcap-screen-pixels",
4351                                 "wsp.header.x-up-devcap-screen-pixels",
4352                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4353                                 "The height and width of the handset's display in pixels.", HFILL
4354                         }
4355                 },
4356                 { &hf_wsp_header_openwave_devcap_em_size,
4357                         {       "x-up-devcap-em-size",
4358                                 "wsp.header.x-up-devcap-em-size",
4359                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4360                                 "The height and width of an uppercase M in pixels in a handset.", HFILL
4361                         }
4362                 },
4363                 { &hf_wsp_header_openwave_devcap_screen_depth,
4364                         {       "x-up-devcap-screen-depth",
4365                                 "wsp.header.x-up-devcap-screen-depth",
4366                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4367                                 "The colour/gray depth of the display in bits.", HFILL
4368                         }
4369                 },
4370                 { &hf_wsp_header_openwave_devcap_immed_alert,
4371                         {       "x-up-devcap-immed-alert",
4372                                 "wsp.header.x-up-devcap-immed-alert",
4373                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4374                                 "Indicates if the handset has support for immediate UPNOTIFY alerts.", HFILL
4375                         }
4376                 },
4377                 { &hf_wsp_header_openwave_proxy_net_ask,
4378                         {       "x-up-proxy-net-ask",
4379                                 "wsp.header.x-up-proxy-net-ask",
4380                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4381                                 "Indicates to browser if circuit switched call is allowed without user interaction", HFILL
4382                         }
4383                 },
4384                 { &hf_wsp_header_openwave_proxy_uplink_version,
4385                         {       "x-up-proxy-uplink-version",
4386                                 "wsp.header.x-up-proxy-uplink-version",
4387                                  FT_STRING, BASE_NONE, NULL, 0x00,
4388                                 "Version of the MAG WAP gateway", HFILL
4389                         }
4390                 },
4391                 { &hf_wsp_header_openwave_proxy_tod,
4392                         {       "x-up-proxy-tod",
4393                                 "wsp.header.x-up-proxy-tod",
4394                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4395                                 "Time of day", HFILL
4396                         }
4397                 },
4398                 { &hf_wsp_header_openwave_proxy_ba_enable,
4399                         {       "x-up-proxy-ba-enable",
4400                                 "wsp.header.x-up-proxy-ba-enable",
4401                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4402                                 "Indicates if the WAP gateway should cache basic authentication details on behalf of the handset", HFILL
4403                         }
4404                 },
4405                 { &hf_wsp_header_openwave_proxy_ba_realm,
4406                         {       "x-up-proxy-ba-realm",
4407                                 "wsp.header.x-up-proxy-ba-realm",
4408                                  FT_STRING, BASE_NONE, NULL, 0x00,
4409                                 "Indicates the realm within which basic authentication credentials apply", HFILL
4410                         }
4411                 },
4412                 { &hf_wsp_header_openwave_proxy_redirect_enable,
4413                         {       "x-up-proxy-redirect-enable",
4414                                 "wsp.header.x-up-proxy-redirect-enable",
4415                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4416                                 "Indicates if the handset wants the WAP gateway to handle HTTP redirects on its behalf", HFILL
4417                         }
4418                 },
4419                 { &hf_wsp_header_openwave_proxy_request_uri,
4420                         {       "x-up-proxy-request-uri",
4421                                 "wsp.header.x-up-proxy-request-uri",
4422                                  FT_STRING, BASE_NONE, NULL, 0x00,
4423                                 "Indicates to the handset that the previous request was redirected to the specified URI", HFILL
4424                         }
4425                 },
4426                 { &hf_wsp_header_openwave_proxy_redirect_status,
4427                         {       "x-up-proxy-redirect-status",
4428                                 "wsp.header.x-up-proxy-redirect-status",
4429                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4430                                 "Indicates the status of a redirect performed on behalf of a handset", HFILL
4431                         }
4432                 },
4433                 { &hf_wsp_header_openwave_proxy_trans_charset,
4434                         {       "x-up-proxy-trans-charset",
4435                                 "wsp.header.x-up-proxy-trans-charset",
4436                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
4437                                 "For POSTs indicates the charset encoding of a document", HFILL
4438                         }
4439                 },
4440                 { &hf_wsp_header_openwave_proxy_trans_charset_str,
4441                         {       "x-up-proxy-trans-charset",
4442                                 "wsp.header.x-up-proxy-trans-charset.string",
4443                                  FT_STRING, BASE_NONE, NULL, 0x00,
4444                                 "For POSTs indicates the charset encoding of a document", HFILL
4445                         }
4446                 },
4447                 { &hf_wsp_header_openwave_proxy_linger,
4448                         {       "x-up-proxy-linger",
4449                                 "wsp.header.x-up-proxy-linger",
4450                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4451                                 "Indicates the circuit linger time in seconds", HFILL
4452                         }
4453                 },
4454                 { &hf_wsp_header_openwave_proxy_client_id,
4455                         {       "x-up-proxy-client-id",
4456                                 "wsp.header.x-up-proxy-client-id",
4457                                  FT_BYTES, BASE_DEC, NULL, 0x00,
4458                                 "The ClientId of the handset", HFILL
4459                         }
4460                 },
4461                 { &hf_wsp_header_openwave_proxy_enable_trust,
4462                         {       "x-up-proxy-enable-trust",
4463                                 "wsp.header.x-up-proxy-enable-trust",
4464                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4465                                 "Indicates whether to enable Trusted Provisioning Domain", HFILL
4466                         }
4467                 },
4468                 { &hf_wsp_header_openwave_proxy_trust_old,
4469                         {       "x-up-proxy-trust-old",
4470                                 "wsp.header.x-up-proxy-trust-old",
4471                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4472                                 "Indicates if the content being returned was received from within the Trusted Provisioning Domain", HFILL
4473                         }
4474                 },
4475                 { &hf_wsp_header_openwave_proxy_trust,
4476                         {       "x-up-proxy-trust",
4477                                 "wsp.header.x-up-proxy-trust",
4478                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4479                                 "Indicates if the content being returned was received from within the Trusted Provisioning Domain", HFILL
4480                         }
4481                 },
4482                 { &hf_wsp_header_openwave_proxy_bookmark,
4483                         {       "x-up-proxy-bookmark",
4484                                 "wsp.header.x-up-proxy-bookmark",
4485                                  FT_STRING, BASE_NONE, NULL, 0x00,
4486                                 "Specifies the URL to use for server-side bookmarks", HFILL
4487                         }
4488                 },
4489                 { &hf_wsp_header_openwave_devcap_gui,
4490                         {       "x-up-devcap-gui",
4491                                 "wsp.header.x-up-devcap-gui",
4492                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4493                                 "Indicates if the handset has a GUI", HFILL
4494                         }
4495                 },
4496                 { &hf_wsp_header_bearer_indication,
4497                         /*
4498                          * XXX - I'm assuming that the bearer indication is
4499                          * just a bearer type.
4500                          */
4501                         {       "Bearer-indication",           
4502                                 "wsp.header.bearer_indication",
4503                                  FT_UINT32, BASE_HEX, VALS(vals_bearer_types), 0x00,
4504                                 "Bearer-indication", HFILL
4505                         }
4506                 },
4507                 { &hf_wsp_header_cache_control,
4508                         {       "Cache-Control",           
4509                                 "wsp.header.cache_control",
4510                                  FT_UINT8, BASE_HEX, VALS ( vals_cache_control ), 0x00,
4511                                 "Cache-Control", HFILL
4512                         }
4513                 },
4514                 { &hf_wsp_header_cache_control_str,
4515                         {       "Cache-Control",           
4516                                 "wsp.header.cache_control.string",
4517                                  FT_STRING, BASE_NONE, NULL, 0x00,
4518                                 "Cache-Control", HFILL
4519                         }
4520                 },
4521                 { &hf_wsp_header_cache_control_field_name,
4522                         {       "Field Name",
4523                                 "wsp.header.cache_control.field_name",
4524                                  FT_UINT8, BASE_HEX, VALS ( vals_field_names ), 0x00,
4525                                 "Cache-Control field name", HFILL
4526                         }
4527                 },
4528                 { &hf_wsp_header_cache_control_field_name_str,
4529                         {       "Field Name",
4530                                 "wsp.header.cache_control.field_name.str",
4531                                  FT_STRING, BASE_NONE, NULL, 0x00,
4532                                 "Cache-Control field name", HFILL
4533                         }
4534                 },
4535                 { &hf_wsp_header_connection,
4536                         {       "Connection",           
4537                                 "wsp.header.connection",
4538                                  FT_UINT8, BASE_HEX, VALS ( vals_connection ), 0x00,
4539                                 "Connection", HFILL
4540                         }
4541                 },
4542                 { &hf_wsp_header_connection_str,
4543                         {       "Connection",           
4544                                 "wsp.header.connection_str",
4545                                  FT_STRING, BASE_NONE, NULL, 0x00,
4546                                 "Connection", HFILL
4547                         }
4548                 },
4549                 { &hf_wsp_header_content_length,
4550                         {       "Content-Length",           
4551                                 "wsp.header.content_length",
4552                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4553                                 "Content-Length", HFILL
4554                         }
4555                 },
4556                 { &hf_wsp_header_date,
4557                         {       "Date",           
4558                                 "wsp.header.date",
4559                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
4560                                 "Date", HFILL
4561                         }
4562                 },
4563                 { &hf_wsp_header_etag,
4564                         {       "Etag",           
4565                                 "wsp.header.etag",
4566                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
4567                                  FT_STRING, BASE_NONE, NULL, 0x00,
4568                                 "Etag", HFILL
4569                         }
4570                 },
4571                 { &hf_wsp_header_expires,
4572                         {       "Expires",           
4573                                 "wsp.header.expires",
4574                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
4575                                 "Expires", HFILL
4576                         }
4577                 },
4578                 { &hf_wsp_header_last_modified,
4579                         {       "Last-Modified",           
4580                                 "wsp.header.last_modified",
4581                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
4582                                 "Last-Modified", HFILL
4583                         }
4584                 },
4585                 { &hf_wsp_header_location,
4586                         {       "Location",           
4587                                 "wsp.header.location",
4588                                  FT_STRING, BASE_NONE, NULL, 0x00,
4589                                 "Location", HFILL
4590                         }
4591                 },
4592                 { &hf_wsp_header_if_modified_since,
4593                         {       "If-Modified-Since",           
4594                                 "wsp.header.if_modified_since",
4595                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
4596                                 "If-Modified-Since", HFILL
4597                         }
4598                 },
4599                 { &hf_wsp_header_pragma,
4600                         {       "Pragma",           
4601                                 "wsp.header.pragma",
4602                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
4603                                  FT_STRING, BASE_NONE, NULL, 0x00,
4604                                 "pragma", HFILL
4605                         }
4606                 },
4607                 { &hf_wsp_header_profile,
4608                         {       "Profile",           
4609                                 "wsp.header.profile",
4610                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
4611                                  FT_STRING, BASE_NONE, NULL, 0x00,
4612                                 "Profile", HFILL
4613                         }
4614                 },
4615                 { &hf_wsp_header_server,
4616                         {       "Server",           
4617                                 "wsp.header.server",
4618                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
4619                                  FT_STRING, BASE_NONE, NULL, 0x00,
4620                                 "Server", HFILL
4621                         }
4622                 },
4623                 { &hf_wsp_header_transfer_encoding,
4624                         {       "Transfer Encoding",           
4625                                 "wsp.header.transfer_enc",
4626                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
4627                                  FT_UINT8, BASE_HEX, VALS ( vals_transfer_encoding ), 0x00,
4628                                 "Transfer Encoding", HFILL
4629                         }
4630                 },
4631                 { &hf_wsp_header_transfer_encoding_str,
4632                         {       "Transfer Encoding",           
4633                                 "wsp.header.transfer_enc_str",
4634                                  FT_STRING, BASE_NONE, NULL, 0x00,
4635                                 "Transfer Encoding", HFILL
4636                         }
4637                 },
4638                 { &hf_wsp_header_user_agent,
4639                         {       "User-Agent",           
4640                                 "wsp.header.user_agent",
4641                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
4642                                  FT_STRING, BASE_NONE, NULL, 0x00,
4643                                 "User-Agent", HFILL
4644                         }
4645                 },
4646                 { &hf_wsp_header_via,
4647                         {       "Via",           
4648                                 "wsp.header.via",
4649                                  FT_STRING, BASE_NONE, NULL, 0x00,
4650                                 "Via", HFILL
4651                         }
4652                 },
4653                 { &hf_wsp_header_wap_application_id,
4654                         {       "X-Wap-Application-Id",           
4655                                 "wsp.header.wap_application_id",
4656                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4657                                 "WAP application id", HFILL
4658                         }
4659                 },
4660                 { &hf_wsp_header_wap_application_id_str,
4661                         {       "X-Wap-Application-Id",           
4662                                 "wsp.header.wap_application_id.string",
4663                                  FT_STRING, BASE_NONE, NULL, 0x00,
4664                                 "WAP application id", HFILL
4665                         }
4666                 },
4667                 { &hf_wsp_header_warning,
4668                         {       "Warning",
4669                                 "wsp.header.warning",
4670                                  FT_NONE, BASE_NONE, NULL, 0x00,
4671                                 "Warning", HFILL
4672                         }
4673                 },
4674                 { &hf_wsp_header_warning_code,
4675                         {       "Warning Code",
4676                                 "wsp.header.warning.code",
4677                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4678                                 "Warning Code", HFILL
4679                         }
4680                 },
4681                 { &hf_wsp_header_warning_agent,
4682                         {       "Warning Agent",
4683                                 "wsp.header.warning.agent",
4684                                  FT_STRING, BASE_NONE, NULL, 0x00,
4685                                 "Warning Agent", HFILL
4686                         }
4687                 },
4688                 { &hf_wsp_header_warning_text,
4689                         {       "Warning Text",
4690                                 "wsp.header.warning.text",
4691                                  FT_STRING, BASE_NONE, NULL, 0x00,
4692                                 "Warning Text", HFILL
4693                         }
4694                 },
4695                 { &hf_wsp_header_application_header,
4696                         {       "Application Header",           
4697                                 "wsp.header.application_header",
4698                                  FT_STRING, BASE_NONE, NULL, 0x00,
4699                                 "Application Header", HFILL
4700                         }
4701                 },
4702                 { &hf_wsp_header_application_value,
4703                         {       "Application Header Value",           
4704                                 "wsp.header.application_header.value",
4705                                  FT_STRING, BASE_NONE, NULL, 0x00,
4706                                 "Application Header Value", HFILL
4707                         }
4708                 },
4709                 { &hf_wsp_header_content_ID,
4710                         {       "Content-ID",           
4711                                 "wsp.header.content-id",
4712                                  FT_STRING, BASE_NONE, NULL, 0x00,
4713                                 "Content-ID", HFILL
4714                         }
4715                 },
4716                 { &hf_wsp_header_x_wap_tod,
4717                         {       "X-WAP.TOD",           
4718                                 "wsp.header.x_wap_tod",
4719                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
4720                                 "X-WAP.TOD", HFILL
4721                         }
4722                 },
4723                 { &hf_wsp_capabilities_client_SDU,
4724                         {       "Client SDU",
4725                                 "wsp.capabilities.client_SDU",
4726                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4727                                 "Client SDU", HFILL
4728                         }
4729                 },
4730                 { &hf_wsp_capabilities_server_SDU,
4731                         {       "Server SDU",
4732                                 "wsp.capabilities.server_SDU",
4733                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4734                                 "Server SDU", HFILL
4735                         }
4736                 },
4737                 { &hf_wsp_capabilities_protocol_opt,
4738                         {       "Protocol Options",
4739                                 "wsp.capabilities.protocol_opt",
4740                                  FT_STRING, BASE_HEX, NULL, 0x00,
4741                                 "Protocol Options", HFILL
4742                         }
4743                 },
4744                 { &hf_wsp_capabilities_method_MOR,
4745                         {       "Method MOR",
4746                                 "wsp.capabilities.method_mor",
4747                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4748                                 "Method MOR", HFILL
4749                         }
4750                 },
4751                 { &hf_wsp_capabilities_push_MOR,
4752                         {       "Push MOR",
4753                                 "wsp.capabilities.push_mor",
4754                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4755                                 "Push MOR", HFILL
4756                         }
4757                 },
4758                 { &hf_wsp_capabilities_extended_methods,
4759                         {       "Extended Methods",
4760                                 "wsp.capabilities.extend_methods",
4761                                  FT_STRING, BASE_HEX, NULL, 0x00,
4762                                 "Extended Methods", HFILL
4763                         }
4764                 },
4765                 { &hf_wsp_capabilities_header_code_pages,
4766                         {       "Header Code Pages",
4767                                 "wsp.capabilities.code_pages",
4768                                  FT_STRING, BASE_HEX, NULL, 0x00,
4769                                 "Header Code Pages", HFILL
4770                         }
4771                 },
4772                 { &hf_wsp_capabilities_aliases,
4773                         {       "Aliases",
4774                                 "wsp.capabilities.aliases",
4775                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4776                                 "Aliases", HFILL
4777                         }
4778                 },
4779                 { &hf_wsp_post_data,
4780                         {       "Post Data",           
4781                                 "wsp.post.data",
4782                                  FT_NONE, BASE_NONE, NULL, 0x00,
4783                                 "Post Data", HFILL
4784                         }
4785                 },
4786                 { &hf_wsp_push_data,
4787                         {       "Push Data",           
4788                                 "wsp.push.data",
4789                                  FT_NONE, BASE_NONE, NULL, 0x00,
4790                                 "Push Data", HFILL
4791                         }
4792                 },
4793                 { &hf_wsp_multipart_data,
4794                         {       "Data in this part",           
4795                                 "wsp.multipart.data",
4796                                  FT_NONE, BASE_NONE, NULL, 0x00,
4797                                 "The data of 1 MIME-multipart part.", HFILL
4798                         }
4799                 },
4800                 { &hf_wsp_mpart,
4801                         {       "Part",           
4802                                 "wsp.multipart",
4803                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4804                                 "MIME part of multipart data.", HFILL
4805                         }
4806                 },
4807                 { &hf_wsp_redirect_flags,
4808                         {       "Flags",
4809                                 "wsp.redirect_flags",
4810                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4811                                 "Redirect Flags", HFILL
4812                         }
4813                 },
4814                 { &hf_wsp_redirect_permanent,
4815                         {       "Permanent Redirect",
4816                                 "wsp.redirect_flags.permanent",
4817                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), PERMANENT_REDIRECT,
4818                                 "Permanent Redirect", HFILL
4819                         }
4820                 },
4821                 { &hf_wsp_redirect_reuse_security_session,
4822                         {       "Reuse Security Session",
4823                                 "wsp.redirect_flags.reuse_security_session",
4824                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), REUSE_SECURITY_SESSION,
4825                                 "Permanent Redirect", HFILL
4826                         }
4827                 },
4828                 { &hf_wsp_redirect_afl,
4829                         {       "Flags/Length",
4830                                 "wsp.redirect_afl",
4831                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4832                                 "Redirect Address Flags/Length", HFILL
4833                         }
4834                 },
4835                 { &hf_wsp_redirect_afl_bearer_type_included,
4836                         {       "Bearer Type Included",
4837                                 "wsp.redirect_afl.bearer_type_included",
4838                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), BEARER_TYPE_INCLUDED,
4839                                 "Redirect Address bearer type included", HFILL
4840                         }
4841                 },
4842                 { &hf_wsp_redirect_afl_port_number_included,
4843                         {       "Port Number Included",
4844                                 "wsp.redirect_afl.port_number_included",
4845                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), PORT_NUMBER_INCLUDED,
4846                                 "Redirect Address port number included", HFILL
4847                         }
4848                 },
4849                 { &hf_wsp_redirect_afl_address_len,
4850                         {       "Address Len",
4851                                 "wsp.redirect_afl.address_len",
4852                                  FT_UINT8, BASE_DEC, NULL, ADDRESS_LEN,
4853                                 "Redirect Address Length", HFILL
4854                         }
4855                 },
4856                 { &hf_wsp_redirect_bearer_type,
4857                         {       "Bearer Type",
4858                                 "wsp.redirect_bearer_type",
4859                                  FT_UINT8, BASE_HEX, VALS(vals_bearer_types), 0x0,
4860                                 "Redirect Bearer Type", HFILL
4861                         }
4862                 },
4863                 { &hf_wsp_redirect_port_num,
4864                         {       "Port Number",
4865                                 "wsp.redirect_port_num",
4866                                  FT_UINT16, BASE_DEC, NULL, 0x0,
4867                                 "Redirect Port Number", HFILL
4868                         }
4869                 },
4870                 { &hf_wsp_redirect_ipv4_addr,
4871                         {       "IP Address",
4872                                 "wsp.redirect_ipv4_addr",
4873                                  FT_IPv4, BASE_NONE, NULL, 0x0,
4874                                 "Redirect Address (IP)", HFILL
4875                         }
4876                 },
4877                 { &hf_wsp_redirect_ipv6_addr,
4878                         {       "IPv6 Address",
4879                                 "wsp.redirect_ipv6_addr",
4880                                  FT_IPv6, BASE_NONE, NULL, 0x0,
4881                                 "Redirect Address (IPv6)", HFILL
4882                         }
4883                 },
4884                 { &hf_wsp_redirect_addr,
4885                         {       "Address",
4886                                 "wsp.redirect_addr",
4887                                  FT_BYTES, BASE_NONE, NULL, 0x0,
4888                                 "Redirect Address", HFILL
4889                         }
4890                 },
4891         };
4892         
4893 /* Setup protocol subtree array */
4894         static gint *ett[] = {
4895                 &ett_wsp,
4896                 &ett_content_type_parameters,
4897                 &ett_header,
4898                 &ett_headers,
4899                 &ett_header_warning,
4900                 &ett_header_cache_control_parameters,
4901                 &ett_header_cache_control_field_names,
4902                 &ett_capabilities,
4903                 &ett_content_type,
4904                 &ett_redirect_flags,
4905                 &ett_redirect_afl,
4906                 &ett_multiparts,
4907                 &ett_mpartlist
4908         };
4909
4910 /* Register the protocol name and description */
4911         proto_wsp = proto_register_protocol(
4912                 "Wireless Session Protocol",    /* protocol name for use by ethereal */ 
4913                 "WSP",                          /* short version of name */
4914                 "wap-wsp"                       /* Abbreviated protocol name, should Match IANA 
4915                                                     < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
4916                                                   */
4917         );
4918
4919 /* Required function calls to register the header fields and subtrees used  */
4920         proto_register_field_array(proto_wsp, hf, array_length(hf));
4921         proto_register_subtree_array(ett, array_length(ett));
4922
4923         register_dissector("wsp-co", dissect_wsp_fromwap_co, proto_wsp);
4924         register_dissector("wsp-cl", dissect_wsp_fromwap_cl, proto_wsp);
4925         wsp_dissector_table = register_dissector_table("wsp.content_type.type",
4926             "WSP content type", FT_UINT8, BASE_HEX);
4927         register_heur_dissector_list("wsp", &heur_subdissector_list);
4928
4929         wsp_fromudp_handle = create_dissector_handle(dissect_wsp_fromudp,
4930             proto_wsp);
4931 };
4932
4933 void
4934 proto_reg_handoff_wsp(void)
4935 {
4936         /*
4937          * Get a handle for the WMLC dissector.
4938          */
4939         wmlc_handle = find_dissector("wmlc");   /* Coming soon :) */
4940
4941         /*
4942          * And get a handle for the WTP-over-UDP dissector.
4943          */
4944         wtp_fromudp_handle = find_dissector("wtp-udp");
4945
4946         /* Only connection-less WSP has no previous handler */
4947         dissector_add("udp.port", UDP_PORT_WSP, wsp_fromudp_handle);
4948         dissector_add("udp.port", UDP_PORT_WSP_PUSH, wsp_fromudp_handle);
4949
4950         /* This dissector is also called from the WTP and WTLS dissectors */
4951 }