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