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