Removed trailing whitespaces from .h and .c files using the
[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.61 2002/08/07 08:34:55 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * WAP dissector based on original work by Ben Fowler
12  * Updated by Neil Hunter <neil.hunter@energis-squared.com>
13  * WTLS support by Alexandre P. Ferreira (Splice IP)
14  * Openwave header support by Dermot Bradley <dermot.bradley@openwave.com>
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  * 
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * 
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #ifdef 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 */