warning: ISO C does not allow extra ; outside of a function
[obnox/wireshark/wip.git] / packet-wsp.c
1 /* packet-wsp.c
2  *
3  * Routines to dissect WSP component of WAP traffic.
4  *
5  * $Id: packet-wsp.c,v 1.100 2003/12/21 05:51:34 jmayer Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * WAP dissector based on original work by Ben Fowler
12  * Updated by Neil Hunter <neil.hunter@energis-squared.com>
13  * WTLS support by Alexandre P. Ferreira (Splice IP)
14  * Openwave header support by Dermot Bradley <dermot.bradley@openwave.com>
15  * Code optimizations, header value dissection simplification with parse error
16  * notification and macros, extra missing headers, WBXML registration,
17  * Session Initiation Request dissection
18  * by Olivier Biot <olivier.biot(ad)siemens.com>.
19  *
20  * TODO - Move parts of dissection before and other parts after "if (tree)",
21  * for example skip almost all but content type in replies if tree is closed.
22  *
23  * This program is free software; you can redistribute it and/or
24  * modify it under the terms of the GNU General Public License
25  * as published by the Free Software Foundation; either version 2
26  * of the License, or (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  */
37
38 /* Edit with a 4-space tabulation */
39
40 #ifdef HAVE_CONFIG_H
41 # include "config.h"
42 #endif
43
44 #include <stdio.h>
45 #include <stdlib.h>
46
47 #ifdef NEED_SNPRINTF_H
48 # include "snprintf.h"
49 #endif
50
51 #include <string.h>
52 #include <glib.h>
53 #include <epan/packet.h>
54 #include <epan/ipv6-utils.h>
55 #include <epan/conversation.h>
56
57 #include "packet-wap.h"
58 #include "packet-wsp.h"
59
60 #define PLURALIZE(x)    ( (x) == 1 ? "" : "s" )
61
62 /* General-purpose debug logger.
63  * Requires double parentheses because of variable arguments of printf().
64  *
65  * Enable debug logging for WSP by defining AM_CFLAGS
66  * so that it contains "-DDEBUG_wsp"
67  */
68 #ifdef DEBUG_wsp
69 #define DebugLog(x) \
70         printf("%s:%u: ", __FILE__, __LINE__); \
71         printf x; \
72         fflush(stdout)
73 #else
74 #define DebugLog(x) ;
75 #endif
76
77 /* Statistics (see doc/README.tapping) */
78 #include "tap.h"
79 static int wsp_tap = -1;
80
81
82 /* File scoped variables for the protocol and registered fields */
83 static int proto_wsp                                    = HF_EMPTY;
84
85 /*
86  * Initialize the header field pointers
87  */
88
89 /* WSP header fields and their subfields if available */
90 static int hf_hdr_name                                  = HF_EMPTY;
91 static int hf_hdr_accept                                = HF_EMPTY;
92 static int hf_hdr_accept_charset                = HF_EMPTY;
93 static int hf_hdr_accept_encoding               = HF_EMPTY;
94 static int hf_hdr_accept_language               = HF_EMPTY;
95 static int hf_hdr_accept_ranges                 = HF_EMPTY;
96 static int hf_hdr_age                                   = HF_EMPTY;
97 static int hf_hdr_allow                                 = HF_EMPTY;
98 static int hf_hdr_authorization                 = HF_EMPTY;
99 static int hf_hdr_authorization_scheme                  = HF_EMPTY; /* Subfield */
100 static int hf_hdr_authorization_user_id                 = HF_EMPTY; /* Subfield */
101 static int hf_hdr_authorization_password                = HF_EMPTY; /* Subfield */
102 static int hf_hdr_cache_control                 = HF_EMPTY;
103 static int hf_hdr_connection                    = HF_EMPTY;
104 static int hf_hdr_content_base                  = HF_EMPTY;
105 static int hf_hdr_content_encoding              = HF_EMPTY;
106 static int hf_hdr_content_language              = HF_EMPTY;
107 static int hf_hdr_content_length                = HF_EMPTY;
108 static int hf_hdr_content_location              = HF_EMPTY;
109 static int hf_hdr_content_md5                   = HF_EMPTY;
110 static int hf_hdr_content_range                 = HF_EMPTY;
111 static int hf_hdr_content_range_first_byte_pos  = HF_EMPTY; /* Subfield */
112 static int hf_hdr_content_range_entity_length   = HF_EMPTY; /* Subfield */
113 static int hf_hdr_content_type                  = HF_EMPTY;
114 static int hf_hdr_date                                  = HF_EMPTY;
115 static int hf_hdr_etag                                  = HF_EMPTY;
116 static int hf_hdr_expires                               = HF_EMPTY;
117 static int hf_hdr_from                                  = HF_EMPTY;
118 static int hf_hdr_host                                  = HF_EMPTY;
119 static int hf_hdr_if_modified_since             = HF_EMPTY;
120 static int hf_hdr_if_match                              = HF_EMPTY;
121 static int hf_hdr_if_none_match                 = HF_EMPTY;
122 static int hf_hdr_if_range                              = HF_EMPTY;
123 static int hf_hdr_if_unmodified_since   = HF_EMPTY;
124 static int hf_hdr_last_modified                 = HF_EMPTY;
125 static int hf_hdr_location                              = HF_EMPTY;
126 static int hf_hdr_max_forwards                  = HF_EMPTY;
127 static int hf_hdr_pragma                                = HF_EMPTY;
128 static int hf_hdr_proxy_authenticate    = HF_EMPTY;
129 static int hf_hdr_proxy_authenticate_scheme             = HF_EMPTY; /* Subfield */
130 static int hf_hdr_proxy_authenticate_realm              = HF_EMPTY; /* Subfield */
131 static int hf_hdr_proxy_authorization   = HF_EMPTY;
132 static int hf_hdr_proxy_authorization_scheme    = HF_EMPTY; /* Subfield */
133 static int hf_hdr_proxy_authorization_user_id   = HF_EMPTY; /* Subfield */
134 static int hf_hdr_proxy_authorization_password  = HF_EMPTY; /* Subfield */
135 static int hf_hdr_public                                = HF_EMPTY;
136 static int hf_hdr_range                                 = HF_EMPTY;
137 static int hf_hdr_range_first_byte_pos                  = HF_EMPTY; /* Subfield */
138 static int hf_hdr_range_last_byte_pos                   = HF_EMPTY; /* Subfield */
139 static int hf_hdr_range_suffix_length                   = HF_EMPTY; /* Subfield */
140 static int hf_hdr_referer                               = HF_EMPTY;
141 static int hf_hdr_retry_after                   = HF_EMPTY;
142 static int hf_hdr_server                                = HF_EMPTY;
143 static int hf_hdr_transfer_encoding             = HF_EMPTY;
144 static int hf_hdr_upgrade                               = HF_EMPTY;
145 static int hf_hdr_user_agent                    = HF_EMPTY;
146 static int hf_hdr_vary                                  = HF_EMPTY;
147 static int hf_hdr_via                                   = HF_EMPTY;
148 static int hf_hdr_warning                               = HF_EMPTY;
149 static int hf_hdr_warning_code                                  = HF_EMPTY; /* Subfield */
150 static int hf_hdr_warning_agent                                 = HF_EMPTY; /* Subfield */
151 static int hf_hdr_warning_text                                  = HF_EMPTY; /* Subfield */
152 static int hf_hdr_www_authenticate              = HF_EMPTY;
153 static int hf_hdr_www_authenticate_scheme               = HF_EMPTY; /* Subfield */
154 static int hf_hdr_www_authenticate_realm                = HF_EMPTY; /* Subfield */
155 static int hf_hdr_content_disposition   = HF_EMPTY;
156 static int hf_hdr_application_id                = HF_EMPTY;
157 static int hf_hdr_content_uri                   = HF_EMPTY;
158 static int hf_hdr_initiator_uri                 = HF_EMPTY;
159 static int hf_hdr_bearer_indication             = HF_EMPTY;
160 static int hf_hdr_push_flag                             = HF_EMPTY;
161 static int hf_hdr_push_flag_auth                                = HF_EMPTY; /* Subfield */
162 static int hf_hdr_push_flag_trust                               = HF_EMPTY; /* Subfield */
163 static int hf_hdr_push_flag_last                                = HF_EMPTY; /* Subfield */
164 static int hf_hdr_profile                               = HF_EMPTY;
165 static int hf_hdr_profile_diff                  = HF_EMPTY;
166 static int hf_hdr_profile_warning               = HF_EMPTY;
167 static int hf_hdr_expect                                = HF_EMPTY;
168 static int hf_hdr_te                                    = HF_EMPTY;
169 static int hf_hdr_trailer                               = HF_EMPTY;
170 static int hf_hdr_x_wap_tod                             = HF_EMPTY;
171 static int hf_hdr_content_id                    = HF_EMPTY;
172 static int hf_hdr_set_cookie                    = HF_EMPTY;
173 static int hf_hdr_cookie                                = HF_EMPTY;
174 static int hf_hdr_encoding_version              = HF_EMPTY;
175 static int hf_hdr_x_wap_security                = HF_EMPTY;
176 static int hf_hdr_x_wap_application_id  = HF_EMPTY;
177 static int hf_hdr_accept_application    = HF_EMPTY;
178
179
180 /* Openwave headers */
181 static int hf_hdr_openwave_x_up_proxy_operator_domain   = HF_EMPTY;
182 static int hf_hdr_openwave_x_up_proxy_home_page                 = HF_EMPTY;
183 static int hf_hdr_openwave_x_up_proxy_uplink_version    = HF_EMPTY;
184 static int hf_hdr_openwave_x_up_proxy_ba_realm                  = HF_EMPTY;
185 static int hf_hdr_openwave_x_up_proxy_request_uri               = HF_EMPTY;
186 #if 0
187 static int hf_hdr_openwave_x_up_proxy_client_id                 = HF_EMPTY;
188 #endif
189 static int hf_hdr_openwave_x_up_proxy_bookmark                  = HF_EMPTY;
190 static int hf_hdr_openwave_x_up_proxy_push_seq                  = HF_EMPTY;
191 static int hf_hdr_openwave_x_up_proxy_notify                    = HF_EMPTY;
192 static int hf_hdr_openwave_x_up_proxy_net_ask                   = HF_EMPTY;
193 static int hf_hdr_openwave_x_up_proxy_tod                               = HF_EMPTY;
194 static int hf_hdr_openwave_x_up_proxy_ba_enable                 = HF_EMPTY;
195 static int hf_hdr_openwave_x_up_proxy_redirect_enable   = HF_EMPTY;
196 static int hf_hdr_openwave_x_up_proxy_redirect_status   = HF_EMPTY;
197 static int hf_hdr_openwave_x_up_proxy_linger                    = HF_EMPTY;
198 static int hf_hdr_openwave_x_up_proxy_enable_trust              = HF_EMPTY;
199 static int hf_hdr_openwave_x_up_proxy_trust                             = HF_EMPTY;
200 static int hf_hdr_openwave_x_up_devcap_has_color                = HF_EMPTY;
201 static int hf_hdr_openwave_x_up_devcap_num_softkeys             = HF_EMPTY;
202 static int hf_hdr_openwave_x_up_devcap_softkey_size             = HF_EMPTY;
203 static int hf_hdr_openwave_x_up_devcap_screen_chars             = HF_EMPTY;
204 static int hf_hdr_openwave_x_up_devcap_screen_pixels    = HF_EMPTY;
205 static int hf_hdr_openwave_x_up_devcap_em_size                  = HF_EMPTY;
206 static int hf_hdr_openwave_x_up_devcap_screen_depth             = HF_EMPTY;
207 static int hf_hdr_openwave_x_up_devcap_immed_alert              = HF_EMPTY;
208 static int hf_hdr_openwave_x_up_devcap_gui                              = HF_EMPTY;
209 static int hf_hdr_openwave_x_up_proxy_trans_charset             = HF_EMPTY;
210 static int hf_hdr_openwave_x_up_proxy_push_accept               = HF_EMPTY;
211
212
213 /* WSP parameter fields */
214 static int hf_parameter_q                                       = HF_EMPTY;
215 static int hf_parameter_charset                         = HF_EMPTY;
216 #if 0
217 static int hf_parameter_textual                         = HF_EMPTY;
218 static int hf_parameter_type                            = HF_EMPTY;
219 static int hf_parameter_name                            = HF_EMPTY;
220 static int hf_parameter_filename                        = HF_EMPTY;
221 static int hf_parameter_start                           = HF_EMPTY;
222 static int hf_parameter_start_info                      = HF_EMPTY;
223 static int hf_parameter_comment                         = HF_EMPTY;
224 static int hf_parameter_domain                          = HF_EMPTY;
225 static int hf_parameter_path                            = HF_EMPTY;
226 static int hf_parameter_sec                                     = HF_EMPTY;
227 static int hf_parameter_mac                                     = HF_EMPTY;
228 static int hf_parameter_upart_type                      = HF_EMPTY;
229 static int hf_parameter_upart_type_value        = HF_EMPTY;
230 static int hf_parameter_level                           = HF_EMPTY;
231 #endif
232
233 /* Old header fields */
234
235 static int hf_wsp_header_tid                            = HF_EMPTY;
236 static int hf_wsp_header_pdu_type                       = HF_EMPTY;
237 static int hf_wsp_version_major                         = HF_EMPTY;
238 static int hf_wsp_version_minor                         = HF_EMPTY;
239 /* Session capabilities (CO-WSP) */
240 static int hf_capabilities_length               = HF_EMPTY;
241 static int hf_capabilities_section              = HF_EMPTY;
242 static int hf_capa_client_sdu_size              = HF_EMPTY;
243 static int hf_capa_server_sdu_size              = HF_EMPTY;
244 static int hf_capa_protocol_options             = HF_EMPTY;
245 static int hf_capa_protocol_option_confirmed_push               = HF_EMPTY; /* Subfield */
246 static int hf_capa_protocol_option_push                                 = HF_EMPTY; /* Subfield */
247 static int hf_capa_protocol_option_session_resume               = HF_EMPTY; /* Subfield */
248 static int hf_capa_protocol_option_ack_headers                  = HF_EMPTY; /* Subfield */
249 static int hf_capa_protocol_option_large_data_transfer  = HF_EMPTY; /* Subfield */
250 static int hf_capa_method_mor                   = HF_EMPTY;
251 static int hf_capa_push_mor                             = HF_EMPTY;
252 static int hf_capa_extended_methods             = HF_EMPTY;
253 static int hf_capa_header_code_pages    = HF_EMPTY;
254 static int hf_capa_aliases                              = HF_EMPTY;
255 static int hf_capa_client_message_size  = HF_EMPTY;
256 static int hf_capa_server_message_size  = HF_EMPTY;
257
258 static int hf_wsp_header_uri_len                        = HF_EMPTY;
259 static int hf_wsp_header_uri                            = HF_EMPTY;
260 static int hf_wsp_server_session_id                     = HF_EMPTY;
261 static int hf_wsp_header_status                         = HF_EMPTY;
262 static int hf_wsp_header_length                         = HF_EMPTY;
263 static int hf_wsp_headers_section                       = HF_EMPTY;
264 static int hf_wsp_parameter_type                        = HF_EMPTY;
265 static int hf_wsp_parameter_name                        = HF_EMPTY;
266 static int hf_wsp_parameter_filename                    = HF_EMPTY;
267 static int hf_wsp_parameter_start                       = HF_EMPTY;
268 static int hf_wsp_parameter_start_info                  = HF_EMPTY;
269 static int hf_wsp_parameter_comment                     = HF_EMPTY;
270 static int hf_wsp_parameter_domain                      = HF_EMPTY;
271 static int hf_wsp_parameter_path                        = HF_EMPTY;
272 static int hf_wsp_parameter_sec                 = HF_EMPTY;
273 static int hf_wsp_parameter_mac                 = HF_EMPTY;
274 static int hf_wsp_parameter_upart_type                  = HF_EMPTY;
275 static int hf_wsp_parameter_level                       = HF_EMPTY;
276 static int hf_wsp_reply_data                            = HF_EMPTY;
277 static int hf_wsp_post_data                             = HF_EMPTY;
278 static int hf_wsp_push_data                             = HF_EMPTY;
279 static int hf_wsp_multipart_data                        = HF_EMPTY;
280 static int hf_wsp_mpart                                 = HF_EMPTY;
281
282 /* Header code page shift sequence */
283 static int hf_wsp_header_shift_code                     = HF_EMPTY;
284
285 /* WSP Redirect fields */
286 static int hf_wsp_redirect_flags                                        = HF_EMPTY;
287 static int hf_wsp_redirect_permanent                            = HF_EMPTY;
288 static int hf_wsp_redirect_reuse_security_session       = HF_EMPTY;
289 static int hf_redirect_addresses                                        = HF_EMPTY;
290
291 /* Address fields */
292 static int hf_address_entry                             = HF_EMPTY;
293 static int hf_address_flags_length              = HF_EMPTY;
294 static int hf_address_flags_length_bearer_type_included = HF_EMPTY; /* Subfield */
295 static int hf_address_flags_length_port_number_included = HF_EMPTY; /* Subfield */
296 static int hf_address_flags_length_address_len                  = HF_EMPTY; /* Subfield */
297 static int hf_address_bearer_type               = HF_EMPTY;
298 static int hf_address_port_num                  = HF_EMPTY;
299 static int hf_address_ipv4_addr                 = HF_EMPTY;
300 static int hf_address_ipv6_addr                 = HF_EMPTY;
301 static int hf_address_addr                              = HF_EMPTY;
302
303 /* Session Initiation Request fields */
304 static int hf_sir_section                                       = HF_EMPTY;
305 static int hf_sir_version                                       = HF_EMPTY;
306 static int hf_sir_app_id_list_len                       = HF_EMPTY;
307 static int hf_sir_app_id_list                           = HF_EMPTY;
308 static int hf_sir_wsp_contact_points_len        = HF_EMPTY;
309 static int hf_sir_wsp_contact_points            = HF_EMPTY;
310 static int hf_sir_contact_points_len            = HF_EMPTY;
311 static int hf_sir_contact_points                        = HF_EMPTY;
312 static int hf_sir_protocol_options_len          = HF_EMPTY;
313 static int hf_sir_protocol_options                      = HF_EMPTY;
314 static int hf_sir_prov_url_len                          = HF_EMPTY;
315 static int hf_sir_prov_url                                      = HF_EMPTY;
316 static int hf_sir_cpi_tag_len                           = HF_EMPTY;
317 static int hf_sir_cpi_tag                                       = HF_EMPTY;
318
319 /*
320  * Initialize the subtree pointers
321  */
322
323 /* WSP tree */
324 static int ett_wsp                                              = ETT_EMPTY;
325 /* WSP headers tree */
326 static int ett_header                                   = ETT_EMPTY;
327 /* WSP header subtree */
328 static int ett_headers                                  = ETT_EMPTY;
329 /* CO-WSP session capabilities */
330 static int ett_capabilities                             = ETT_EMPTY;
331 static int ett_capability                               = ETT_EMPTY;
332 static int ett_post                                             = ETT_EMPTY;
333 static int ett_redirect_flags                   = ETT_EMPTY;
334 static int ett_address_flags                    = ETT_EMPTY;
335 static int ett_multiparts                               = ETT_EMPTY;
336 static int ett_mpartlist                                = ETT_EMPTY;
337 /* Session Initiation Request tree */
338 static int ett_sir                                              = ETT_EMPTY;
339 static int ett_addresses                                = ETT_EMPTY;
340 static int ett_address                                  = ETT_EMPTY;
341
342
343
344 /* Handle for WSP-over-UDP dissector */
345 static dissector_handle_t wsp_fromudp_handle;
346
347 /* Handle for WTP-over-UDP dissector */
348 static dissector_handle_t wtp_fromudp_handle;
349
350 const value_string vals_pdu_type[] = {
351         { 0x00, "Reserved" },
352         { 0x01, "Connect" },
353         { 0x02, "ConnectReply" },
354         { 0x03, "Redirect" },
355         { 0x04, "Reply" },
356         { 0x05, "Disconnect" },
357         { 0x06, "Push" },
358         { 0x07, "ConfirmedPush" },
359         { 0x08, "Suspend" },
360         { 0x09, "Resume" },
361
362         /* 0x10 - 0x3F Unassigned */
363
364         { 0x40, "Get" },
365         { 0x41, "Options" },
366         { 0x42, "Head" },
367         { 0x43, "Delete" },
368         { 0x44, "Trace" },
369
370         /* 0x45 - 0x4F Unassigned (Get PDU) */
371         /* 0x50 - 0x5F Extended method (Get PDU) */
372         { 0x50, "Extended Get Method 0"},
373         { 0x51, "Extended Get Method 1"},
374         { 0x52, "Extended Get Method 2"},
375         { 0x53, "Extended Get Method 3"},
376         { 0x54, "Extended Get Method 4"},
377         { 0x55, "Extended Get Method 5"},
378         { 0x56, "Extended Get Method 6"},
379         { 0x57, "Extended Get Method 7"},
380         { 0x58, "Extended Get Method 8"},
381         { 0x59, "Extended Get Method 9"},
382         { 0x5A, "Extended Get Method 10"},
383         { 0x5B, "Extended Get Method 11"},
384         { 0x5C, "Extended Get Method 12"},
385         { 0x5D, "Extended Get Method 13"},
386         { 0x5E, "Extended Get Method 14"},
387         { 0x5F, "Extended Get Method 15"},
388
389         { 0x60, "Post" },
390         { 0x61, "Put" },
391
392         /* 0x62 - 0x6F Unassigned (Post PDU) */
393         /* 0x70 - 0x7F Extended method (Post PDU) */
394         { 0x70, "Extended Post Method 0"},
395         { 0x71, "Extended Post Method 1"},
396         { 0x72, "Extended Post Method 2"},
397         { 0x73, "Extended Post Method 3"},
398         { 0x74, "Extended Post Method 4"},
399         { 0x75, "Extended Post Method 5"},
400         { 0x76, "Extended Post Method 6"},
401         { 0x77, "Extended Post Method 7"},
402         { 0x78, "Extended Post Method 8"},
403         { 0x79, "Extended Post Method 9"},
404         { 0x7A, "Extended Post Method 10"},
405         { 0x7B, "Extended Post Method 11"},
406         { 0x7C, "Extended Post Method 12"},
407         { 0x7D, "Extended Post Method 13"},
408         { 0x7E, "Extended Post Method 14"},
409         { 0x7F, "Extended Post Method 15"},
410
411         /* 0x80 - 0xFF Reserved */
412
413         { 0x00, NULL }
414
415 };
416
417 /* The WSP status codes are inherited from the HTTP status codes */
418 const value_string vals_status[] = {
419         /* 0x00 - 0x0F Reserved */
420
421         { 0x10, "100 Continue" },
422         { 0x11, "101 Switching Protocols" },
423
424         { 0x20, "200 OK" },
425         { 0x21, "201 Created" },
426         { 0x22, "202 Accepted" },
427         { 0x23, "203 Non-Authoritative Information" },
428         { 0x24, "204 No Content" },
429         { 0x25, "205 Reset Content" },
430         { 0x26, "206 Partial Content" },
431
432         { 0x30, "300 Multiple Choices" },
433         { 0x31, "301 Moved Permanently" },
434         { 0x32, "302 Moved Temporarily" },
435         { 0x33, "303 See Other" },
436         { 0x34, "304 Not Modified" },
437         { 0x35, "305 Use Proxy" },
438         { 0x37, "307 Temporary Redirect" },
439
440         { 0x40, "400 Bad Request" },
441         { 0x41, "401 Unauthorised" },
442         { 0x42, "402 Payment Required" },
443         { 0x43, "403 Forbidden" },
444         { 0x44, "404 Not Found" },
445         { 0x45, "405 Method Not Allowed" },
446         { 0x46, "406 Not Acceptable" },
447         { 0x47, "407 Proxy Authentication Required" },
448         { 0x48, "408 Request Timeout" },
449         { 0x49, "409 Conflict" },
450         { 0x4A, "410 Gone" },
451         { 0x4B, "411 Length Required" },
452         { 0x4C, "412 Precondition Failed" },
453         { 0x4D, "413 Request Entity Too Large" },
454         { 0x4E, "414 Request-URI Too Large" },
455         { 0x4F, "415 Unsupported Media Type" },
456         { 0x50, "416 Requested Range Not Satisfiable" },
457         { 0x51, "417 Expectation Failed" },
458
459         { 0x60, "500 Internal Server Error" },
460         { 0x61, "501 Not Implemented" },
461         { 0x62, "502 Bad Gateway" },
462         { 0x63, "503 Service Unavailable" },
463         { 0x64, "504 Gateway Timeout" },
464         { 0x65, "505 WSP/HTTP Version Not Supported" },
465
466         { 0x00, NULL }
467 };
468
469 const value_string vals_wsp_reason_codes[] = {
470         { 0xE0, "Protocol Error (Illegal PDU)" },
471         { 0xE1, "Session disconnected" },
472         { 0xE2, "Session suspended" },
473         { 0xE3, "Session resumed" },
474         { 0xE4, "Peer congested" },
475         { 0xE5, "Session connect failed" },
476         { 0xE6, "Maximum receive unit size exceeded" },
477         { 0xE7, "Maximum outstanding requests exceeded" },
478         { 0xE8, "Peer request" },
479         { 0xE9, "Network error" },
480         { 0xEA, "User request" },
481         { 0xEB, "No specific cause, no retries" },
482         { 0xEC, "Push message cannot be delivered" },
483         { 0xED, "Push message discarded" },
484         { 0xEE, "Content type cannot be processed" },
485
486         { 0x00, NULL }
487 };
488
489 /*
490  * Field names.
491  */
492 #define FN_ACCEPT               0x00
493 #define FN_ACCEPT_CHARSET_DEP   0x01    /* encoding version 1.1, deprecated */
494 #define FN_ACCEPT_ENCODING_DEP  0x02    /* encoding version 1.1, deprecated */
495 #define FN_ACCEPT_LANGUAGE      0x03
496 #define FN_ACCEPT_RANGES        0x04
497 #define FN_AGE                  0x05
498 #define FN_ALLOW                0x06
499 #define FN_AUTHORIZATION        0x07
500 #define FN_CACHE_CONTROL_DEP    0x08    /* encoding version 1.1, deprecated */
501 #define FN_CONNECTION           0x09
502 #define FN_CONTENT_BASE         0x0A
503 #define FN_CONTENT_ENCODING     0x0B
504 #define FN_CONTENT_LANGUAGE     0x0C
505 #define FN_CONTENT_LENGTH       0x0D
506 #define FN_CONTENT_LOCATION     0x0E
507 #define FN_CONTENT_MD5          0x0F
508 #define FN_CONTENT_RANGE_DEP    0x10    /* encoding version 1.1, deprecated */
509 #define FN_CONTENT_TYPE         0x11
510 #define FN_DATE                 0x12
511 #define FN_ETAG                 0x13
512 #define FN_EXPIRES              0x14
513 #define FN_FROM                 0x15
514 #define FN_HOST                 0x16
515 #define FN_IF_MODIFIED_SINCE    0x17
516 #define FN_IF_MATCH             0x18
517 #define FN_IF_NONE_MATCH        0x19
518 #define FN_IF_RANGE             0x1A
519 #define FN_IF_UNMODIFIED_SINCE  0x1B
520 #define FN_LOCATION             0x1C
521 #define FN_LAST_MODIFIED        0x1D
522 #define FN_MAX_FORWARDS         0x1E
523 #define FN_PRAGMA               0x1F
524 #define FN_PROXY_AUTHENTICATE   0x20
525 #define FN_PROXY_AUTHORIZATION  0x21
526 #define FN_PUBLIC               0x22
527 #define FN_RANGE                0x23
528 #define FN_REFERER              0x24
529 #define FN_RETRY_AFTER          0x25
530 #define FN_SERVER               0x26
531 #define FN_TRANSFER_ENCODING    0x27
532 #define FN_UPGRADE              0x28
533 #define FN_USER_AGENT           0x29
534 #define FN_VARY                 0x2A
535 #define FN_VIA                  0x2B
536 #define FN_WARNING              0x2C
537 #define FN_WWW_AUTHENTICATE     0x2D
538 #define FN_CONTENT_DISPOSITION  0x2E
539 #define FN_X_WAP_APPLICATION_ID 0x2F
540 #define FN_X_WAP_CONTENT_URI    0x30
541 #define FN_X_WAP_INITIATOR_URI  0x31
542 #define FN_ACCEPT_APPLICATION   0x32
543 #define FN_BEARER_INDICATION    0x33
544 #define FN_PUSH_FLAG            0x34
545 #define FN_PROFILE              0x35
546 #define FN_PROFILE_DIFF         0x36
547 #define FN_PROFILE_WARNING      0x37
548 #define FN_EXPECT               0x38
549 #define FN_TE                   0x39
550 #define FN_TRAILER              0x3A
551 #define FN_ACCEPT_CHARSET       0x3B    /* encoding version 1.3 */
552 #define FN_ACCEPT_ENCODING      0x3C    /* encoding version 1.3 */
553 #define FN_CACHE_CONTROL        0x3D    /* encoding version 1.3 */
554 #define FN_CONTENT_RANGE        0x3E    /* encoding version 1.3 */
555 #define FN_X_WAP_TOD            0x3F
556 #define FN_CONTENT_ID           0x40
557 #define FN_SET_COOKIE           0x41
558 #define FN_COOKIE               0x42
559 #define FN_ENCODING_VERSION     0x43
560 #define FN_PROFILE_WARNING14    0x44    /* encoding version 1.4 */
561 #define FN_CONTENT_DISPOSITION14        0x45    /* encoding version 1.4 */
562 #define FN_X_WAP_SECURITY       0x46
563 #define FN_CACHE_CONTROL14      0x47    /* encoding version 1.4 */
564 #define FN_EXPECT15 0x48        /* encoding version 1.5 */
565 #define FN_X_WAP_LOC_INVOCATION 0x49
566 #define FN_X_WAP_LOC_DELIVERY 0x4A
567
568
569 /*
570  * Openwave field names.
571  */
572 #define FN_OPENWAVE_PROXY_PUSH_ADDR             0x00
573 #define FN_OPENWAVE_PROXY_PUSH_ACCEPT           0x01
574 #define FN_OPENWAVE_PROXY_PUSH_SEQ              0x02
575 #define FN_OPENWAVE_PROXY_NOTIFY                0x03
576 #define FN_OPENWAVE_PROXY_OPERATOR_DOMAIN       0x04
577 #define FN_OPENWAVE_PROXY_HOME_PAGE             0x05
578 #define FN_OPENWAVE_DEVCAP_HAS_COLOR            0x06
579 #define FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS         0x07
580 #define FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE         0x08
581 #define FN_OPENWAVE_DEVCAP_SCREEN_CHARS         0x09
582 #define FN_OPENWAVE_DEVCAP_SCREEN_PIXELS        0x0A
583 #define FN_OPENWAVE_DEVCAP_EM_SIZE              0x0B
584 #define FN_OPENWAVE_DEVCAP_SCREEN_DEPTH         0x0C
585 #define FN_OPENWAVE_DEVCAP_IMMED_ALERT          0x0D
586 #define FN_OPENWAVE_PROXY_NET_ASK               0x0E
587 #define FN_OPENWAVE_PROXY_UPLINK_VERSION        0x0F
588 #define FN_OPENWAVE_PROXY_TOD                   0x10
589 #define FN_OPENWAVE_PROXY_BA_ENABLE             0x11
590 #define FN_OPENWAVE_PROXY_BA_REALM              0x12
591 #define FN_OPENWAVE_PROXY_REDIRECT_ENABLE       0x13
592 #define FN_OPENWAVE_PROXY_REQUEST_URI           0x14
593 #define FN_OPENWAVE_PROXY_REDIRECT_STATUS       0x15
594 #define FN_OPENWAVE_PROXY_TRANS_CHARSET         0x16
595 #define FN_OPENWAVE_PROXY_LINGER                0x17
596 #define FN_OPENWAVE_PROXY_CLIENT_ID             0x18
597 #define FN_OPENWAVE_PROXY_ENABLE_TRUST          0x19
598 #define FN_OPENWAVE_PROXY_TRUST_OLD             0x1A
599 #define FN_OPENWAVE_PROXY_TRUST                 0x20
600 #define FN_OPENWAVE_PROXY_BOOKMARK              0x21
601 #define FN_OPENWAVE_DEVCAP_GUI                  0x22
602
603 static const value_string vals_openwave_field_names[] = {
604         { FN_OPENWAVE_PROXY_PUSH_ADDR,         "x-up-proxy-push-addr" },
605         { FN_OPENWAVE_PROXY_PUSH_ACCEPT,       "x-up-proxy-push-accept" },
606         { FN_OPENWAVE_PROXY_PUSH_SEQ,          "x-up-proxy-seq" },
607         { FN_OPENWAVE_PROXY_NOTIFY,            "x-up-proxy-notify" },
608         { FN_OPENWAVE_PROXY_OPERATOR_DOMAIN,   "x-up-proxy-operator-domain" },
609         { FN_OPENWAVE_PROXY_HOME_PAGE,         "x-up-proxy-home-page" },
610         { FN_OPENWAVE_DEVCAP_HAS_COLOR,        "x-up-devcap-has-color" },
611         { FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS,     "x-up-devcap-num-softkeys" },
612         { FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE,     "x-up-devcap-softkey-size" },
613         { FN_OPENWAVE_DEVCAP_SCREEN_CHARS,     "x-up-devcap-screen-chars" },
614         { FN_OPENWAVE_DEVCAP_SCREEN_PIXELS,    "x-up-devcap-screen-pixels" },
615         { FN_OPENWAVE_DEVCAP_EM_SIZE,          "x-up-devcap-em-size" },
616         { FN_OPENWAVE_DEVCAP_SCREEN_DEPTH,     "x-up-devcap-screen-depth" },
617         { FN_OPENWAVE_DEVCAP_IMMED_ALERT,      "x-up-devcap-immed-alert" },
618         { FN_OPENWAVE_PROXY_NET_ASK,           "x-up-proxy-net-ask" },
619         { FN_OPENWAVE_PROXY_UPLINK_VERSION,    "x-up-proxy-uplink-version" },
620         { FN_OPENWAVE_PROXY_TOD,               "x-up-proxy-tod" },
621         { FN_OPENWAVE_PROXY_BA_ENABLE,         "x-up-proxy-ba-enable" },
622         { FN_OPENWAVE_PROXY_BA_REALM,          "x-up-proxy-ba-realm" },
623         { FN_OPENWAVE_PROXY_REDIRECT_ENABLE,   "x-up-proxy-redirect-enable" },
624         { FN_OPENWAVE_PROXY_REQUEST_URI,       "x-up-proxy-request-uri" },
625         { FN_OPENWAVE_PROXY_REDIRECT_STATUS,   "x-up-proxy-redirect-status" },
626         { FN_OPENWAVE_PROXY_TRANS_CHARSET,     "x-up-proxy-trans-charset" },
627         { FN_OPENWAVE_PROXY_LINGER,            "x-up-proxy-linger" },
628         { FN_OPENWAVE_PROXY_CLIENT_ID,         "x-up-proxy-client-id" },
629         { FN_OPENWAVE_PROXY_ENABLE_TRUST,      "x-up-proxy-enable-trust" },
630         { FN_OPENWAVE_PROXY_TRUST_OLD,         "x-up-proxy-trust-old" },
631         { FN_OPENWAVE_PROXY_TRUST,             "x-up-proxy-trust" },
632         { FN_OPENWAVE_PROXY_BOOKMARK,          "x-up-proxy-bookmark" },
633         { FN_OPENWAVE_DEVCAP_GUI,              "x-up-devcap-gui" },
634         { 0,                                   NULL }
635 };
636
637
638 static const value_string vals_field_names[] = {
639         { FN_ACCEPT,               "Accept" },
640         { FN_ACCEPT_CHARSET_DEP,   "Accept-Charset (encoding 1.1)" },
641         { FN_ACCEPT_ENCODING_DEP,  "Accept-Encoding (encoding 1.1)" },
642         { FN_ACCEPT_LANGUAGE,      "Accept-Language" },
643         { FN_ACCEPT_RANGES,        "Accept-Ranges" },
644         { FN_AGE,                  "Age" },
645         { FN_ALLOW,                "Allow" },
646         { FN_AUTHORIZATION,        "Authorization" },
647         { FN_CACHE_CONTROL_DEP,    "Cache-Control (encoding 1.1)" },
648         { FN_CONNECTION,           "Connection" },
649         { FN_CONTENT_BASE,         "Content-Base" },
650         { FN_CONTENT_ENCODING,     "Content-Encoding" },
651         { FN_CONTENT_LANGUAGE,     "Content-Language" },
652         { FN_CONTENT_LENGTH,       "Content-Length" },
653         { FN_CONTENT_LOCATION,     "Content-Location" },
654         { FN_CONTENT_MD5,          "Content-MD5" },
655         { FN_CONTENT_RANGE_DEP,    "Content-Range (encoding 1.1)" },
656         { FN_CONTENT_TYPE,         "Content-Type" },
657         { FN_DATE,                 "Date" },
658         { FN_ETAG,                 "ETag" },
659         { FN_EXPIRES,              "Expires" },
660         { FN_FROM,                 "From" },
661         { FN_HOST,                 "Host" },
662         { FN_IF_MODIFIED_SINCE,    "If-Modified-Since" },
663         { FN_IF_MATCH,             "If-Match" },
664         { FN_IF_NONE_MATCH,        "If-None-Match" },
665         { FN_IF_RANGE,             "If-Range" },
666         { FN_IF_UNMODIFIED_SINCE,  "If-Unmodified-Since" },
667         { FN_LOCATION,             "Location" },
668         { FN_LAST_MODIFIED,        "Last-Modified" },
669         { FN_MAX_FORWARDS,         "Max-Forwards" },
670         { FN_PRAGMA,               "Pragma" },
671         { FN_PROXY_AUTHENTICATE,   "Proxy-Authenticate" },
672         { FN_PROXY_AUTHORIZATION,  "Proxy-Authorization" },
673         { FN_PUBLIC,               "Public" },
674         { FN_RANGE,                "Range" },
675         { FN_REFERER,              "Referer" },
676         { FN_RETRY_AFTER,          "Retry-After" },
677         { FN_SERVER,               "Server" },
678         { FN_TRANSFER_ENCODING,    "Transfer-Encoding" },
679         { FN_UPGRADE,              "Upgrade" },
680         { FN_USER_AGENT,           "User-Agent" },
681         { FN_VARY,                 "Vary" },
682         { FN_VIA,                  "Via" },
683         { FN_WARNING,              "Warning" },
684         { FN_WWW_AUTHENTICATE,     "WWW-Authenticate" },
685         { FN_CONTENT_DISPOSITION,  "Content-Disposition" },
686         { FN_X_WAP_APPLICATION_ID, "X-Wap-Application-ID" },
687         { FN_X_WAP_CONTENT_URI,    "X-Wap-Content-URI" },
688         { FN_X_WAP_INITIATOR_URI,  "X-Wap-Initiator-URI" },
689         { FN_ACCEPT_APPLICATION,   "Accept-Application" },
690         { FN_BEARER_INDICATION,    "Bearer-Indication" },
691         { FN_PUSH_FLAG,            "Push-Flag" },
692         { FN_PROFILE,              "Profile" },
693         { FN_PROFILE_DIFF,         "Profile-Diff" },
694         { FN_PROFILE_WARNING,      "Profile-Warning" },
695         { FN_EXPECT,               "Expect" },
696         { FN_TE,                   "TE" },
697         { FN_TRAILER,              "Trailer" },
698         { FN_ACCEPT_CHARSET,       "Accept-Charset" },
699         { FN_ACCEPT_ENCODING,      "Accept-Encoding" },
700         { FN_CACHE_CONTROL,        "Cache-Control" },
701         { FN_CONTENT_RANGE,        "Content-Range" },
702         { FN_X_WAP_TOD,            "X-Wap-Tod" },
703         { FN_CONTENT_ID,           "Content-ID" },
704         { FN_SET_COOKIE,           "Set-Cookie" },
705         { FN_COOKIE,               "Cookie" },
706         { FN_ENCODING_VERSION,     "Encoding-Version" },
707         { FN_PROFILE_WARNING14,    "Profile-Warning (encoding 1.4)" },
708         { FN_CONTENT_DISPOSITION14,"Content-Disposition (encoding 1.4)" },
709         { FN_X_WAP_SECURITY,       "X-WAP-Security" },
710         { FN_CACHE_CONTROL14,      "Cache-Control (encoding 1.4)" },
711         /* encoding-version 1.5 */
712         { FN_EXPECT15,             "Expect (encoding 1.5)" },
713         { FN_X_WAP_LOC_INVOCATION, "X-Wap-Loc-Invocation" },
714         { FN_X_WAP_LOC_DELIVERY,   "X-Wap-Loc-Delivery" },
715         { 0,                       NULL }
716 };
717
718 /*
719  * Bearer types (from the WDP specification).
720  */
721 #define BT_IPv4                 0x00
722 #define BT_IPv6                 0x01
723 #define BT_GSM_USSD             0x02
724 #define BT_GSM_SMS              0x03
725 #define BT_ANSI_136_GUTS        0x04
726 #define BT_IS_95_SMS            0x05
727 #define BT_IS_95_CSD            0x06
728 #define BT_IS_95_PACKET_DATA    0x07
729 #define BT_ANSI_136_CSD         0x08
730 #define BT_ANSI_136_PACKET_DATA 0x09
731 #define BT_GSM_CSD              0x0A
732 #define BT_GSM_GPRS             0x0B
733 #define BT_GSM_USSD_IPv4        0x0C
734 #define BT_AMPS_CDPD            0x0D
735 #define BT_PDC_CSD              0x0E
736 #define BT_PDC_PACKET_DATA      0x0F
737 #define BT_IDEN_SMS             0x10
738 #define BT_IDEN_CSD             0x11
739 #define BT_IDEN_PACKET_DATA     0x12
740 #define BT_PAGING_FLEX          0x13
741 #define BT_PHS_SMS              0x14
742 #define BT_PHS_CSD              0x15
743 #define BT_GSM_USSD_GSM_SC      0x16
744 #define BT_TETRA_SDS_ITSI       0x17
745 #define BT_TETRA_SDS_MSISDN     0x18
746 #define BT_TETRA_PACKET_DATA    0x19
747 #define BT_PAGING_REFLEX        0x1A
748 #define BT_GSM_USSD_MSISDN      0x1B
749 #define BT_MOBITEX_MPAK         0x1C
750 #define BT_ANSI_136_GHOST       0x1D
751
752 static const value_string vals_bearer_types[] = {
753         { BT_IPv4,                 "IPv4" },
754         { BT_IPv6,                 "IPv6" },
755         { BT_GSM_USSD,             "GSM USSD" },
756         { BT_GSM_SMS,              "GSM SMS" },
757         { BT_ANSI_136_GUTS,        "ANSI-136 GUTS/R-Data" },
758         { BT_IS_95_SMS,            "IS-95 CDMA SMS" },
759         { BT_IS_95_CSD,            "IS-95 CDMA CSD" },
760         { BT_IS_95_PACKET_DATA,    "IS-95 CDMA Packet data" },
761         { BT_ANSI_136_CSD,         "ANSI-136 CSD" },
762         { BT_ANSI_136_PACKET_DATA, "ANSI-136 Packet data" },
763         { BT_GSM_CSD,              "GSM CSD" },
764         { BT_GSM_GPRS,             "GSM GPRS" },
765         { BT_GSM_USSD_IPv4,        "GSM USSD (IPv4 addresses)" },
766         { BT_AMPS_CDPD,            "AMPS CDPD" },
767         { BT_PDC_CSD,              "PDC CSD" },
768         { BT_PDC_PACKET_DATA,      "PDC Packet data" },
769         { BT_IDEN_SMS,             "IDEN SMS" },
770         { BT_IDEN_CSD,             "IDEN CSD" },
771         { BT_IDEN_PACKET_DATA,     "IDEN Packet data" },
772         { BT_PAGING_FLEX,          "Paging network FLEX(TM)" },
773         { BT_PHS_SMS,              "PHS SMS" },
774         { BT_PHS_CSD,              "PHS CSD" },
775         { BT_GSM_USSD_GSM_SC,      "GSM USSD (GSM Service Code addresses)" },
776         { BT_TETRA_SDS_ITSI,       "TETRA SDS (ITSI addresses)" },
777         { BT_TETRA_SDS_MSISDN,     "TETRA SDS (MSISDN addresses)" },
778         { BT_TETRA_PACKET_DATA,    "TETRA Packet data" },
779         { BT_PAGING_REFLEX,        "Paging network ReFLEX(TM)" },
780         { BT_GSM_USSD_MSISDN,      "GSM USSD (MSISDN addresses)" },
781         { BT_MOBITEX_MPAK,         "Mobitex MPAK" },
782         { BT_ANSI_136_GHOST,       "ANSI-136 GHOST/R-Data" },
783         { 0,                       NULL }
784 };
785
786 static const value_string vals_content_types[] = {
787         /* Well-known media types */
788         { 0x00, "*/*" },
789         { 0x01, "text/*" },
790         { 0x02, "text/html" },
791         { 0x03, "text/plain" },
792         { 0x04, "text/x-hdml" },
793         { 0x05, "text/x-ttml" },
794         { 0x06, "text/x-vCalendar" },
795         { 0x07, "text/x-vCard" },
796         { 0x08, "text/vnd.wap.wml" },
797         { 0x09, "text/vnd.wap.wmlscript" },
798         { 0x0A, "text/vnd.wap.channel" },
799         { 0x0B, "multipart/*" },
800         { 0x0C, "multipart/mixed" },
801         { 0x0D, "multipart/form-data" },
802         { 0x0E, "multipart/byteranges" },
803         { 0x0F, "multipart/alternative" },
804         { 0x10, "application/*" },
805         { 0x11, "application/java-vm" },
806         { 0x12, "application/x-www-form-urlencoded" },
807         { 0x13, "application/x-hdmlc" },
808         { 0x14, "application/vnd.wap.wmlc" },
809         { 0x15, "application/vnd.wap.wmlscriptc" },
810         { 0x16, "application/vnd.wap.channelc" },
811         { 0x17, "application/vnd.wap.uaprof" },
812         { 0x18, "application/vnd.wap.wtls-ca-certificate" },
813         { 0x19, "application/vnd.wap.wtls-user-certificate" },
814         { 0x1A, "application/x-x509-ca-cert" },
815         { 0x1B, "application/x-x509-user-cert" },
816         { 0x1C, "image/*" },
817         { 0x1D, "image/gif" },
818         { 0x1E, "image/jpeg" },
819         { 0x1F, "image/tiff" },
820         { 0x20, "image/png" },
821         { 0x21, "image/vnd.wap.wbmp" },
822         { 0x22, "application/vnd.wap.multipart.*" },
823         { 0x23, "application/vnd.wap.multipart.mixed" },
824         { 0x24, "application/vnd.wap.multipart.form-data" },
825         { 0x25, "application/vnd.wap.multipart.byteranges" },
826         { 0x26, "application/vnd.wap.multipart.alternative" },
827         { 0x27, "application/xml" },
828         { 0x28, "text/xml" },
829         { 0x29, "application/vnd.wap.wbxml" },
830         { 0x2A, "application/x-x968-cross-cert" },
831         { 0x2B, "application/x-x968-ca-cert" },
832         { 0x2C, "application/x-x968-user-cert" },
833         { 0x2D, "text/vnd.wap.si" },
834         { 0x2E, "application/vnd.wap.sic" },
835         { 0x2F, "text/vnd.wap.sl" },
836         { 0x30, "application/vnd.wap.slc" },
837         { 0x31, "text/vnd.wap.co" },
838         { 0x32, "application/vnd.wap.coc" },
839         { 0x33, "application/vnd.wap.multipart.related" },
840         { 0x34, "application/vnd.wap.sia" },
841         { 0x35, "text/vnd.wap.connectivity-xml" },
842         { 0x36, "application/vnd.wap.connectivity-wbxml" },
843         { 0x37, "application/pkcs7-mime" },
844         { 0x38, "application/vnd.wap.hashed-certificate" },
845         { 0x39, "application/vnd.wap.signed-certificate" },
846         { 0x3A, "application/vnd.wap.cert-response" },
847         { 0x3B, "application/xhtml+xml" },
848         { 0x3C, "application/wml+xml" },
849         { 0x3D, "text/css" },
850         { 0x3E, "application/vnd.wap.mms-message" },
851         { 0x3F, "application/vnd.wap.rollover-certificate" },
852         { 0x40, "application/vnd.wap.locc+wbxml"},
853         { 0x41, "application/vnd.wap.loc+xml"},
854         { 0x42, "application/vnd.syncml.dm+wbxml"},
855         { 0x43, "application/vnd.syncml.dm+xml"},
856         { 0x44, "application/vnd.syncml.notification"},
857         { 0x45, "application/vnd.wap.xhtml+xml"},
858         { 0x46, "application/vnd.wv.csp.cir"},
859         { 0x47, "application/vnd.oma.dd+xml"},
860         { 0x48, "application/vnd.oma.drm.message"},
861         { 0x49, "application/vnd.oma.drm.content"},
862         { 0x4A, "application/vnd.oma.drm.rights+xml"},
863         { 0x4B, "application/vnd.oma.drm.rights+wbxml"},
864         { 0x4C, "application/vnd.wv.csp+xml"},
865         { 0x4D, "application/vnd.wv.csp+wbxml"},
866         /* The following media types are registered by 3rd parties */ 
867         { 0x0201, "application/vnd.uplanet.cachop-wbxml" },
868         { 0x0202, "application/vnd.uplanet.signal" },
869         { 0x0203, "application/vnd.uplanet.alert-wbxml" },
870         { 0x0204, "application/vnd.uplanet.list-wbxml" },
871         { 0x0205, "application/vnd.uplanet.listcmd-wbxml" },
872         { 0x0206, "application/vnd.uplanet.channel-wbxml" },
873         { 0x0207, "application/vnd.uplanet.provisioning-status-uri" },
874         { 0x0208, "x-wap.multipart/vnd.uplanet.header-set" },
875         { 0x0209, "application/vnd.uplanet.bearer-choice-wbxml" },
876         { 0x020A, "application/vnd.phonecom.mmc-wbxml" },
877         { 0x020B, "application/vnd.nokia.syncset+wbxml" },
878         { 0x020C, "image/x-up-wpng"},
879         { 0x0300, "application/iota.mmc-wbxml"},
880         { 0x0301, "application/iota.mmc-xml"},
881         { 0x00, NULL }
882 };
883
884 static const value_string vals_languages[] = {
885         { 0x01, "Afar (aa)" },
886         { 0x02, "Abkhazian (ab)" },
887         { 0x03, "Afrikaans (af)" },
888         { 0x04, "Amharic (am)" },
889         { 0x05, "Arabic (ar)" },
890         { 0x06, "Assamese (as)" },
891         { 0x07, "Aymara (ay)" },
892         { 0x08, "Azerbaijani (az)" },
893         { 0x09, "Bashkir (ba)" },
894         { 0x0A, "Byelorussian (be)" },
895         { 0x0B, "Bulgarian (bg)" },
896         { 0x0C, "Bihari (bh)" },
897         { 0x0D, "Bislama (bi)" },
898         { 0x0E, "Bengali; Bangla (bn)" },
899         { 0x0F, "Tibetan (bo)" },
900         { 0x10, "Breton (br)" },
901         { 0x11, "Catalan (ca)" },
902         { 0x12, "Corsican (co)" },
903         { 0x13, "Czech (cs)" },
904         { 0x14, "Welsh (cy)" },
905         { 0x15, "Danish (da)" },
906         { 0x16, "German (de)" },
907         { 0x17, "Bhutani (dz)" },
908         { 0x18, "Greek (el)" },
909         { 0x19, "English (en)" },
910         { 0x1A, "Esperanto (eo)" },
911         { 0x1B, "Spanish (es)" },
912         { 0x1C, "Estonian (et)" },
913         { 0x1D, "Basque (eu)" },
914         { 0x1E, "Persian (fa)" },
915         { 0x1F, "Finnish (fi)" },
916         { 0x20, "Fiji (fj)" },
917         { 0x21, "Urdu (ur)" },
918         { 0x22, "French (fr)" },
919         { 0x23, "Uzbek (uz)" },
920         { 0x24, "Irish (ga)" },
921         { 0x25, "Scots Gaelic (gd)" },
922         { 0x26, "Galician (gl)" },
923         { 0x27, "Guarani (gn)" },
924         { 0x28, "Gujarati (gu)" },
925         { 0x29, "Hausa (ha)" },
926         { 0x2A, "Hebrew (formerly iw) (he)" },
927         { 0x2B, "Hindi (hi)" },
928         { 0x2C, "Croatian (hr)" },
929         { 0x2D, "Hungarian (hu)" },
930         { 0x2E, "Armenian (hy)" },
931         { 0x2F, "Vietnamese (vi)" },
932         { 0x30, "Indonesian (formerly in) (id)" },
933         { 0x31, "Wolof (wo)" },
934         { 0x32, "Xhosa (xh)" },
935         { 0x33, "Icelandic (is)" },
936         { 0x34, "Italian (it)" },
937         { 0x35, "Yoruba (yo)" },
938         { 0x36, "Japanese (ja)" },
939         { 0x37, "Javanese (jw)" },
940         { 0x38, "Georgian (ka)" },
941         { 0x39, "Kazakh (kk)" },
942         { 0x3A, "Zhuang (za)" },
943         { 0x3B, "Cambodian (km)" },
944         { 0x3C, "Kannada (kn)" },
945         { 0x3D, "Korean (ko)" },
946         { 0x3E, "Kashmiri (ks)" },
947         { 0x3F, "Kurdish (ku)" },
948         { 0x40, "Kirghiz (ky)" },
949         { 0x41, "Chinese (zh)" },
950         { 0x42, "Lingala (ln)" },
951         { 0x43, "Laothian (lo)" },
952         { 0x44, "Lithuanian (lt)" },
953         { 0x45, "Latvian, Lettish (lv)" },
954         { 0x46, "Malagasy (mg)" },
955         { 0x47, "Maori (mi)" },
956         { 0x48, "Macedonian (mk)" },
957         { 0x49, "Malayalam (ml)" },
958         { 0x4A, "Mongolian (mn)" },
959         { 0x4B, "Moldavian (mo)" },
960         { 0x4C, "Marathi (mr)" },
961         { 0x4D, "Malay (ms)" },
962         { 0x4E, "Maltese (mt)" },
963         { 0x4F, "Burmese (my)" },
964         { 0x50, "Ukrainian (uk)" },
965         { 0x51, "Nepali (ne)" },
966         { 0x52, "Dutch (nl)" },
967         { 0x53, "Norwegian (no)" },
968         { 0x54, "Occitan (oc)" },
969         { 0x55, "(Afan) Oromo (om)" },
970         { 0x56, "Oriya (or)" },
971         { 0x57, "Punjabi (pa)" },
972         { 0x58, "Polish (po)" },
973         { 0x59, "Pashto, Pushto (ps)" },
974         { 0x5A, "Portuguese (pt)" },
975         { 0x5B, "Quechua (qu)" },
976         { 0x5C, "Zulu (zu)" },
977         { 0x5D, "Kirundi (rn)" },
978         { 0x5E, "Romanian (ro)" },
979         { 0x5F, "Russian (ru)" },
980         { 0x60, "Kinyarwanda (rw)" },
981         { 0x61, "Sanskrit (sa)" },
982         { 0x62, "Sindhi (sd)" },
983         { 0x63, "Sangho (sg)" },
984         { 0x64, "Serbo-Croatian (sh)" },
985         { 0x65, "Sinhalese (si)" },
986         { 0x66, "Slovak (sk)" },
987         { 0x67, "Slovenian (sl)" },
988         { 0x68, "Samoan (sm)" },
989         { 0x69, "Shona (sn)" },
990         { 0x6A, "Somali (so)" },
991         { 0x6B, "Albanian (sq)" },
992         { 0x6C, "Serbian (sr)" },
993         { 0x6D, "Siswati (ss)" },
994         { 0x6E, "Sesotho (st)" },
995         { 0x6F, "Sundanese (su)" },
996         { 0x70, "Swedish (sv)" },
997         { 0x71, "Swahili (sw)" },
998         { 0x72, "Tamil (ta)" },
999         { 0x73, "Telugu (te)" },
1000         { 0x74, "Tajik (tg)" },
1001         { 0x75, "Thai (th)" },
1002         { 0x76, "Tigrinya (ti)" },
1003         { 0x77, "Turkmen (tk)" },
1004         { 0x78, "Tagalog (tl)" },
1005         { 0x79, "Setswana (tn)" },
1006         { 0x7A, "Tonga (to)" },
1007         { 0x7B, "Turkish (tr)" },
1008         { 0x7C, "Tsonga (ts)" },
1009         { 0x7D, "Tatar (tt)" },
1010         { 0x7E, "Twi (tw)" },
1011         { 0x7F, "Uighur (ug)" },
1012         { 0x81, "Nauru (na)" },
1013         { 0x82, "Faeroese (fo)" },
1014         { 0x83, "Frisian (fy)" },
1015         { 0x84, "Interlingua (ia)" },
1016         { 0x85, "Volapuk (vo)" },
1017         { 0x86, "Interlingue (ie)" },
1018         { 0x87, "Inupiak (ik)" },
1019         { 0x88, "Yiddish (formerly ji) (yi)" },
1020         { 0x89, "Inuktitut (iu)" },
1021         { 0x8A, "Greenlandic (kl)" },
1022         { 0x8B, "Latin (la)" },
1023         { 0x8C, "Rhaeto-Romance (rm)" },
1024         { 0x00, NULL }
1025 };
1026
1027
1028 #define CACHE_CONTROL_NO_CACHE                  0x00
1029 #define CACHE_CONTROL_NO_STORE                  0x01
1030 #define CACHE_CONTROL_MAX_AGE                   0x02
1031 #define CACHE_CONTROL_MAX_STALE                 0x03
1032 #define CACHE_CONTROL_MIN_FRESH                 0x04
1033 #define CACHE_CONTROL_ONLY_IF_CACHED    0x05
1034 #define CACHE_CONTROL_PUBLIC                    0x06
1035 #define CACHE_CONTROL_PRIVATE                   0x07
1036 #define CACHE_CONTROL_NO_TRANSFORM              0x08
1037 #define CACHE_CONTROL_MUST_REVALIDATE   0x09
1038 #define CACHE_CONTROL_PROXY_REVALIDATE  0x0A
1039 #define CACHE_CONTROL_S_MAXAGE                  0x0B
1040
1041 static const value_string vals_cache_control[] = {
1042         { CACHE_CONTROL_NO_CACHE,         "no-cache" },
1043         { CACHE_CONTROL_NO_STORE,         "no-store" },
1044         { CACHE_CONTROL_MAX_AGE,          "max-age" },
1045         { CACHE_CONTROL_MAX_STALE,        "max-stale" },
1046         { CACHE_CONTROL_MIN_FRESH,        "min-fresh" },
1047         { CACHE_CONTROL_ONLY_IF_CACHED,   "only-if-cached" },
1048         { CACHE_CONTROL_PUBLIC,           "public" },
1049         { CACHE_CONTROL_PRIVATE,          "private" },
1050         { CACHE_CONTROL_NO_TRANSFORM,     "no-transform" },
1051         { CACHE_CONTROL_MUST_REVALIDATE,  "must-revalidate" },
1052         { CACHE_CONTROL_PROXY_REVALIDATE, "proxy-revalidate" },
1053         { CACHE_CONTROL_S_MAXAGE,         "s-max-age" },
1054
1055         { 0x00, NULL }
1056 };
1057
1058 static const value_string vals_wap_application_ids[] = {
1059         /* Well-known WAP applications */
1060         { 0x00, "x-wap-application:*"},
1061         { 0x01, "x-wap-application:push.sia"},
1062         { 0x02, "x-wap-application:wml.ua"},
1063         { 0x03, "x-wap-application:wta.ua"},
1064         { 0x04, "x-wap-application:mms.ua"},
1065         { 0x05, "x-wap-application:push.syncml"},
1066         { 0x06, "x-wap-application:loc.ua"},
1067         { 0x07, "x-wap-application:syncml.dm"},
1068         { 0x08, "x-wap-application:drm.ua"},
1069         { 0x09, "x-wap-application:emn.ua"},
1070         { 0x0A, "x-wap-application:wv.ua"},
1071         /* Registered by 3rd parties */
1072         { 0x8000, "x-wap-microsoft:localcontent.ua"},
1073         { 0x8001, "x-wap-microsoft:IMclient.ua"},
1074         { 0x8002, "x-wap-docomo:imode.mail.ua"},
1075         { 0x8003, "x-wap-docomo:imode.mr.ua"},
1076         { 0x8004, "x-wap-docomo:imode.mf.ua"},
1077         { 0x8005, "x-motorola:location.ua"},
1078         { 0x8006, "x-motorola:now.ua"},
1079         { 0x8007, "x-motorola:otaprov.ua"},
1080         { 0x8008, "x-motorola:browser.ua"},
1081         { 0x8009, "x-motorola:splash.ua"},
1082         /* 0x800A: unassigned */
1083         { 0x800B, "x-wap-nai:mvsw.command"},
1084         /* 0x800C -- 0x800F: unassigned */
1085         { 0x8010, "x-wap-openwave:iota.ua"},
1086         /* 0x8011 -- 0x8FFF: unassigned */
1087         { 0x9000, "x-wap-docomo:imode.mail2.ua"},
1088         { 0x9001, "x-oma-nec:otaprov.ua"},
1089         { 0x9002, "x-oma-nokia:call.ua"},
1090         { 0x9003, "x-oma-coremobility:sqa.ua"},
1091
1092         { 0x00, NULL }
1093 };
1094
1095
1096 /* Parameters and well-known encodings */
1097 static const value_string vals_wsp_parameter_sec[] = {
1098         { 0x00, "NETWPIN" },
1099         { 0x01, "USERPIN" },
1100         { 0x02, "USERNETWPIN" },
1101         { 0x03, "USERPINMAC" },
1102
1103         { 0x00, NULL }
1104 };
1105
1106 /* Warning codes and mappings */
1107 static const value_string vals_wsp_warning_code[] = {
1108         { 10, "110 Response is stale" },
1109         { 11, "111 Revalidation failed" },
1110         { 12, "112 Disconnected operation" },
1111         { 13, "113 Heuristic expiration" },
1112         { 14, "214 Transformation applied" },
1113         { 99, "199/299 Miscellaneous warning" },
1114
1115         { 0, NULL }
1116 };
1117
1118 static const value_string vals_wsp_warning_code_short[] = {
1119         { 10, "110" },
1120         { 11, "111" },
1121         { 12, "112" },
1122         { 13, "113" },
1123         { 14, "214" },
1124         { 99, "199/299" },
1125
1126         { 0, NULL }
1127 };
1128
1129 /* Profile-Warning codes - see http://www.w3.org/TR/NOTE-CCPPexchange */
1130 static const value_string vals_wsp_profile_warning_code[] = {
1131         { 0x10, "100 OK" },
1132         { 0x11, "101 Used stale profile" },
1133         { 0x12, "102 Not used profile" },
1134         { 0x20, "200 Not applied" },
1135         { 0x21, "101 Content selection applied" },
1136         { 0x22, "202 Content generation applied" },
1137         { 0x23, "203 Transformation applied" },
1138
1139         { 0x00, NULL }
1140 };
1141
1142 /* Well-known TE values */
1143 static const value_string vals_well_known_te[] = {
1144         { 0x82, "chunked" },
1145         { 0x83, "identity" },
1146         { 0x84, "gzip" },
1147         { 0x85, "compress" },
1148         { 0x86, "deflate" },
1149
1150         { 0x00, NULL }
1151 };
1152
1153
1154 /*
1155  * Redirect flags.
1156  */
1157 #define PERMANENT_REDIRECT              0x80
1158 #define REUSE_SECURITY_SESSION  0x40
1159
1160 /*
1161  * Redirect address flags and length.
1162  */
1163 #define BEARER_TYPE_INCLUDED    0x80
1164 #define PORT_NUMBER_INCLUDED    0x40
1165 #define ADDRESS_LEN                             0x3f
1166
1167 static const true_false_string yes_no_truth = {
1168         "Yes" ,
1169         "No"
1170 };
1171
1172 static const value_string vals_false_true[] = {
1173         { 0, "False" },
1174         { 1, "True" },
1175         { 0, NULL },
1176 };
1177
1178 enum {
1179         WSP_PDU_RESERVED                = 0x00,
1180         WSP_PDU_CONNECT                 = 0x01,
1181         WSP_PDU_CONNECTREPLY            = 0x02,
1182         WSP_PDU_REDIRECT                = 0x03,                 /* No sample data */
1183         WSP_PDU_REPLY                   = 0x04,
1184         WSP_PDU_DISCONNECT              = 0x05,
1185         WSP_PDU_PUSH                    = 0x06,                 /* No sample data */
1186         WSP_PDU_CONFIRMEDPUSH           = 0x07,                 /* No sample data */
1187         WSP_PDU_SUSPEND                 = 0x08,                 /* No sample data */
1188         WSP_PDU_RESUME                  = 0x09,                 /* No sample data */
1189
1190         WSP_PDU_GET                     = 0x40,
1191         WSP_PDU_OPTIONS                 = 0x41,                 /* No sample data */
1192         WSP_PDU_HEAD                    = 0x42,                 /* No sample data */
1193         WSP_PDU_DELETE                  = 0x43,                 /* No sample data */
1194         WSP_PDU_TRACE                   = 0x44,                 /* No sample data */
1195
1196         WSP_PDU_POST                    = 0x60,
1197         WSP_PDU_PUT                     = 0x61                  /* No sample data */
1198 };
1199
1200
1201 /* Dissector tables for handoff */
1202 static dissector_table_t media_type_table;
1203 static heur_dissector_list_t heur_subdissector_list;
1204
1205 static void add_uri (proto_tree *, packet_info *, tvbuff_t *, guint, guint);
1206
1207 static void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
1208 static void add_multipart_data (proto_tree *, tvbuff_t *);
1209
1210 static void add_capabilities (proto_tree *tree, tvbuff_t *tvb, guint8 pdu_type);
1211
1212
1213 /*
1214  * Dissect the WSP header part.
1215  * This function calls wkh_XXX functions that dissect well-known headers.
1216  */
1217 static void add_headers (proto_tree *tree, tvbuff_t *tvb, int hf);
1218
1219 /* The following macros define WSP basic data structures as found
1220  * in the ABNF notation of WSP headers.
1221  * Currently all text data types are mapped to text_string.
1222  */
1223 #define is_short_integer(x)             ( (x) & 0x80 )
1224 #define is_long_integer(x)              ( (x) <= 30 )
1225 #define is_date_value(x)                is_long_integer(x)
1226 #define is_integer_value(x)             (is_short_integer(x) || is_long_integer(x))
1227 #define is_delta_seconds_value(x)       is_integer_value(x)
1228 /* Text string == *TEXT 0x00, thus also an empty string matches the rule! */
1229 #define is_text_string(x)       ( ((x) == 0) || ( ((x) >= 32) && ((x) <= 127)) ) 
1230 #define is_quoted_string(x)             ( (x) == 0x22 ) /* " */
1231 #define is_token_text(x)                is_text_string(x)
1232 #define is_text_value(x)                is_text_string(x)
1233 #define is_uri_value(x)                 is_text_string(x)
1234
1235 #define get_uintvar_integer(val,tvb,start,len,ok) \
1236         val = tvb_get_guintvar(tvb,start,&len); \
1237         if (len>5) ok = FALSE; else ok = TRUE;
1238 #define get_short_integer(val,tvb,start,len,ok) \
1239         val = tvb_get_guint8(tvb,start); \
1240         if (val & 0x80) ok = TRUE; else ok=FALSE; \
1241         val &= 0x7F; len = 1;
1242 #define get_long_integer(val,tvb,start,len,ok) \
1243         len = tvb_get_guint8(tvb,start); \
1244         ok = TRUE; /* Valid lengths for us are 1-4 */ \
1245         if (len==1) { val = tvb_get_guint8(tvb,start+1); } \
1246         else if (len==2) { val = tvb_get_ntohs(tvb,start+1); } \
1247         else if (len==3) { val = tvb_get_ntoh24(tvb,start+1); } \
1248         else if (len==4) { val = tvb_get_ntohl(tvb,start+1); } \
1249         else ok = FALSE; \
1250         len++; /* Add the 1st octet to the length */
1251 #define get_integer_value(val,tvb,start,len,ok) \
1252         len = tvb_get_guint8(tvb,start); \
1253         ok = TRUE; \
1254         if (len & 0x80) { val = len & 0x7F; len = 0; } \
1255         else if (len==1) { val = tvb_get_guint8(tvb,start+1); } \
1256         else if (len==2) { val = tvb_get_ntohs(tvb,start+1); } \
1257         else if (len==3) { val = tvb_get_ntoh24(tvb,start+1); } \
1258         else if (len==4) { val = tvb_get_ntohl(tvb,start+1); } \
1259         else ok = FALSE; \
1260         len++; /* Add the 1st octet to the length */
1261 #define get_date_value(val,tvb,start,len,ok) \
1262         get_long_integer(val,tvb,start,len,ok)
1263 #define get_delta_seconds_value(val,tvb,start,len,ok) \
1264         get_integer_value(val,tvb,start,len,ok)
1265
1266 /* NOTE - Don't forget to g_free() the str value after its usage as the
1267  * tvb_get_string[z]() functions return g_malloc()ed memory! */ 
1268 #define get_text_string(str,tvb,start,len,ok) \
1269         if (is_text_string(tvb_get_guint8(tvb,start))) { \
1270                 str = tvb_get_stringz(tvb,start,&len); \
1271                 g_assert (str); \
1272                 ok = TRUE; \
1273         } else { len = 0; str = NULL; ok = FALSE; }
1274 #define get_token_text(str,tvb,start,len,ok) \
1275         get_text_string(str,tvb,start,len,ok)
1276 #define get_extension_media(str,tvb,start,len,ok) \
1277         get_text_string(str,tvb,start,len,ok)
1278 #define get_text_value(str,tvb,start,len,ok) \
1279         get_text_string(str,tvb,start,len,ok)
1280 #define get_quoted_string(str,tvb,start,len,ok) \
1281         get_text_string(str,tvb,start,len,ok)
1282 #define get_uri_value(str,tvb,start,len,ok) \
1283         get_text_string(str,tvb,start,len,ok)
1284
1285 #define get_version_value(val,str,tvb,start,len,ok) \
1286         val = tvb_get_guint8(tvb,start); \
1287         ok = TRUE; \
1288         if (val & 0x80) { /* High nibble "." Low nibble */ \
1289                 len = 1; \
1290                 val &= 0x7F; \
1291                 str = g_strdup_printf("%u.%u", val >> 4, val & 0x0F); \
1292         } else { get_text_string(str,tvb,start,len,ok); }
1293         
1294 /* Parameter parser */
1295 static int
1296 parameter (proto_tree *tree, proto_item *ti, tvbuff_t *tvb, int start, int len);
1297 static int
1298 parameter_value_q (proto_tree *tree, proto_item *ti, tvbuff_t *tvb, int start);
1299
1300 #define InvalidValueForHeader(hdr) \
1301         "<Error: Invalid value for the '" hdr "' header>"
1302 #define InvalidTextualHeader \
1303         "<Error: Invalid zero-length textual header>"
1304 #define TrailingQuoteWarning \
1305         " <Warning: Quoted-string value has been encoded with a trailing quote>"
1306
1307 /* WSP well-known header parsing function prototypes;
1308  * will be listed in the function lookup table WellKnownHeaders[] */
1309 static guint32 wkh_default (proto_tree *tree, tvbuff_t *tvb,
1310                 guint32 hdr_start);
1311 static guint32 wkh_accept (proto_tree *tree, tvbuff_t *tvb,
1312                 guint32 hdr_start);
1313 static guint32 wkh_content_type (proto_tree *tree, tvbuff_t *tvb,
1314                 guint32 hdr_start);
1315 static guint32 wkh_accept_charset (proto_tree *tree, tvbuff_t *tvb,
1316                 guint32 hdr_start);
1317 static guint32 wkh_accept_language (proto_tree *tree, tvbuff_t *tvb,
1318                 guint32 hdr_start);
1319 static guint32 wkh_connection (proto_tree *tree, tvbuff_t *tvb,
1320                 guint32 hdr_start);
1321 static guint32 wkh_push_flag (proto_tree *tree, tvbuff_t *tvb,
1322                 guint32 header_start);
1323 static guint32 wkh_vary (proto_tree *tree, tvbuff_t *tvb,
1324                 guint32 hdr_start);
1325 static guint32 wkh_accept_ranges (proto_tree *tree, tvbuff_t *tvb,
1326                 guint32 hdr_start);
1327 static guint32 wkh_content_disposition (proto_tree *tree, tvbuff_t *tvb,
1328                 guint32 hdr_start);
1329 static guint32 wkh_accept_encoding (proto_tree *tree, tvbuff_t *tvb,
1330                 guint32 hdr_start);
1331 static guint32 wkh_content_encoding (proto_tree *tree, tvbuff_t *tvb,
1332                 guint32 hdr_start);
1333 static guint32 wkh_transfer_encoding (proto_tree *tree, tvbuff_t *tvb,
1334                 guint32 hdr_start);
1335 static guint32 wkh_pragma (proto_tree *tree, tvbuff_t *tvb,
1336                 guint32 hdr_start);
1337 /* Single short-integer value */
1338 static guint32 wkh_x_wap_security (proto_tree *tree, tvbuff_t *tvb,
1339                 guint32 hdr_start);
1340 /* Text */
1341 static guint32 wkh_content_base (proto_tree *tree, tvbuff_t *tvb,
1342                 guint32 hdr_start);
1343 static guint32 wkh_content_location (proto_tree *tree, tvbuff_t *tvb,
1344                 guint32 hdr_start);
1345 static guint32 wkh_etag (proto_tree *tree, tvbuff_t *tvb,
1346                 guint32 hdr_start);
1347 static guint32 wkh_from (proto_tree *tree, tvbuff_t *tvb,
1348                 guint32 hdr_start);
1349 static guint32 wkh_host (proto_tree *tree, tvbuff_t *tvb,
1350                 guint32 hdr_start);
1351 static guint32 wkh_if_match (proto_tree *tree, tvbuff_t *tvb,
1352                 guint32 hdr_start);
1353 static guint32 wkh_if_none_match (proto_tree *tree, tvbuff_t *tvb,
1354                 guint32 hdr_start);
1355 static guint32 wkh_location (proto_tree *tree, tvbuff_t *tvb,
1356                 guint32 hdr_start);
1357 static guint32 wkh_referer (proto_tree *tree, tvbuff_t *tvb,
1358                 guint32 hdr_start);
1359 static guint32 wkh_server (proto_tree *tree, tvbuff_t *tvb,
1360                 guint32 hdr_start);
1361 static guint32 wkh_user_agent (proto_tree *tree, tvbuff_t *tvb,
1362                 guint32 hdr_start);
1363 static guint32 wkh_upgrade (proto_tree *tree, tvbuff_t *tvb,
1364                 guint32 hdr_start);
1365 static guint32 wkh_via (proto_tree *tree, tvbuff_t *tvb,
1366                 guint32 hdr_start);
1367 static guint32 wkh_content_uri (proto_tree *tree, tvbuff_t *tvb,
1368                 guint32 hdr_start);
1369 static guint32 wkh_initiator_uri (proto_tree *tree, tvbuff_t *tvb,
1370                 guint32 hdr_start);
1371 static guint32 wkh_profile (proto_tree *tree, tvbuff_t *tvb,
1372                 guint32 hdr_start);
1373 static guint32 wkh_content_id (proto_tree *tree, tvbuff_t *tvb,
1374                 guint32 hdr_start);
1375 /* Date-value or text */
1376 static guint32 wkh_if_range (proto_tree *tree, tvbuff_t *tvb,
1377                 guint32 hdr_start);
1378 /* Date-value */
1379 static guint32 wkh_date (proto_tree *tree, tvbuff_t *tvb,
1380                 guint32 hdr_start);
1381 static guint32 wkh_expires (proto_tree *tree, tvbuff_t *tvb,
1382                 guint32 hdr_start);
1383 static guint32 wkh_if_modified_since (proto_tree *tree, tvbuff_t *tvb,
1384                 guint32 hdr_start);
1385 static guint32 wkh_if_unmodified_since (proto_tree *tree, tvbuff_t *tvb,
1386                 guint32 hdr_start);
1387 static guint32 wkh_last_modified (proto_tree *tree, tvbuff_t *tvb,
1388                 guint32 hdr_start);
1389 /* Date-value with special meaning */
1390 static guint32 wkh_x_wap_tod (proto_tree *tree, tvbuff_t *tvb,
1391                 guint32 hdr_start);
1392 /* Delta-seconds-value */
1393 static guint32 wkh_age (proto_tree *tree, tvbuff_t *tvb,
1394                 guint32 hdr_start);
1395 /* Challenge */
1396 static guint32 wkh_proxy_authenticate (proto_tree *tree, tvbuff_t *tvb,
1397                 guint32 hdr_start);
1398 static guint32 wkh_www_authenticate (proto_tree *tree, tvbuff_t *tvb,
1399                 guint32 hdr_start);
1400 /* Credentials */
1401 static guint32 wkh_authorization (proto_tree *tree, tvbuff_t *tvb,
1402                 guint32 hdr_start);
1403 static guint32 wkh_proxy_authorization (proto_tree *tree, tvbuff_t *tvb,
1404                 guint32 hdr_start);
1405 /* Pragma */
1406 static guint32 wkh_pragma (proto_tree *tree, tvbuff_t *tvb,
1407                 guint32 hdr_start);
1408 /* Integer-value */
1409 static guint32 wkh_content_length (proto_tree *tree, tvbuff_t *tvb,
1410                 guint32 hdr_start);
1411 static guint32 wkh_max_forwards (proto_tree *tree, tvbuff_t *tvb,
1412                 guint32 hdr_start);
1413
1414 /* Integer lookup value */
1415 static guint32 wkh_bearer_indication (proto_tree *tree, tvbuff_t *tvb,
1416                 guint32 hdr_start);
1417
1418 /* WAP application ID value */
1419 static guint32 wkh_x_wap_application_id (proto_tree *tree, tvbuff_t *tvb,
1420                 guint32 hdr_start);
1421 static guint32 wkh_accept_application (proto_tree *tree, tvbuff_t *tvb,
1422                 guint32 hdr_start);
1423 static guint32 wkh_content_language (proto_tree *tree, tvbuff_t *tvb,
1424                 guint32 hdr_start);
1425
1426 /* Allow and Public */
1427 static guint32 wkh_allow(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start);
1428 static guint32 wkh_public(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start);
1429
1430 /* Cache-control */
1431 static guint32 wkh_cache_control (proto_tree *tree, tvbuff_t *tvb,
1432                 guint32 hdr_start);
1433 /* Warning */
1434 static guint32 wkh_warning (proto_tree *tree, tvbuff_t *tvb,
1435                 guint32 hdr_start);
1436 /* Profile-warning */
1437 static guint32 wkh_profile_warning (proto_tree *tree, tvbuff_t *tvb,
1438                 guint32 hdr_start);
1439
1440 /* Content-MD5 */
1441 static guint32 wkh_content_md5 (proto_tree *tree, tvbuff_t *tvb,
1442                 guint32 hdr_start);
1443
1444 /* WSP encoding version */
1445 static guint32 wkh_encoding_version (proto_tree *tree, tvbuff_t *tvb,
1446                 guint32 hdr_start);
1447
1448 /* Content-Range and Range */
1449 static guint32 wkh_content_range (proto_tree *tree, tvbuff_t *tvb,
1450                 guint32 hdr_start);
1451 static guint32 wkh_range (proto_tree *tree, tvbuff_t *tvb,
1452                 guint32 hdr_start);
1453
1454 /* TE */
1455 static guint32 wkh_te (proto_tree *tree, tvbuff_t *tvb,
1456                 guint32 hdr_start);
1457
1458 /* Header value */
1459 static guint32 wkh_trailer (proto_tree *tree, tvbuff_t *tvb,
1460                 guint32 hdr_start);
1461
1462 /* TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
1463 static guint32 wkh_retry_after (proto_tree *tree, tvbuff_t *tvb,
1464                 guint32 hdr_start);
1465 static guint32 wkh_profile_diff (proto_tree *tree, tvbuff_t *tvb,
1466                 guint32 hdr_start);
1467 static guint32 wkh_expect (proto_tree *tree, tvbuff_t *tvb,
1468                 guint32 hdr_start);
1469 static guint32 wkh_set_cookie (proto_tree *tree, tvbuff_t *tvb,
1470                 guint32 hdr_start);
1471 static guint32 wkh_cookie (proto_tree *tree, tvbuff_t *tvb,
1472                 guint32 hdr_start);
1473 */
1474
1475
1476 /* WSP well-known Openwave header parsing function prototypes;
1477  * will be listed in the function lookup table WellKnownOpenwaveHeaders[] */
1478 static guint32 wkh_openwave_default (proto_tree *tree, tvbuff_t *tvb,
1479                 guint32 hdr_start);
1480 /* Textual headers */
1481 static guint32 wkh_openwave_x_up_proxy_operator_domain(proto_tree *tree,
1482                 tvbuff_t *tvb, guint32 hdr_start);
1483 static guint32 wkh_openwave_x_up_proxy_home_page(proto_tree *tree,
1484                 tvbuff_t *tvb, guint32 hdr_start);
1485 static guint32 wkh_openwave_x_up_proxy_uplink_version(proto_tree *tree,
1486                 tvbuff_t *tvb, guint32 hdr_start);
1487 static guint32 wkh_openwave_x_up_proxy_ba_realm(proto_tree *tree,
1488                 tvbuff_t *tvb, guint32 hdr_start);
1489 static guint32 wkh_openwave_x_up_proxy_request_uri(proto_tree *tree,
1490                 tvbuff_t *tvb, guint32 hdr_start);
1491 static guint32 wkh_openwave_x_up_proxy_bookmark(proto_tree *tree,
1492                 tvbuff_t *tvb, guint32 hdr_start);
1493 /* Integer headers */
1494 static guint32 wkh_openwave_x_up_proxy_push_seq(proto_tree *tree,
1495                 tvbuff_t *tvb, guint32 hdr_start);
1496 static guint32 wkh_openwave_x_up_proxy_notify(proto_tree *tree,
1497                 tvbuff_t *tvb, guint32 hdr_start);
1498 static guint32 wkh_openwave_x_up_proxy_net_ask(proto_tree *tree,
1499                 tvbuff_t *tvb, guint32 hdr_start);
1500 static guint32 wkh_openwave_x_up_proxy_tod (proto_tree *tree,
1501                 tvbuff_t *tvb, guint32 hdr_start);
1502 static guint32 wkh_openwave_x_up_proxy_ba_enable(proto_tree *tree,
1503                 tvbuff_t *tvb, guint32 hdr_start);
1504 static guint32 wkh_openwave_x_up_proxy_redirect_enable(proto_tree *tree,
1505                 tvbuff_t *tvb, guint32 hdr_start);
1506 static guint32 wkh_openwave_x_up_proxy_redirect_status(proto_tree *tree,
1507                 tvbuff_t *tvb, guint32 hdr_start);
1508 static guint32 wkh_openwave_x_up_proxy_linger(proto_tree *tree,
1509                 tvbuff_t *tvb, guint32 hdr_start);
1510 static guint32 wkh_openwave_x_up_proxy_enable_trust(proto_tree *tree,
1511                 tvbuff_t *tvb, guint32 hdr_start);
1512 static guint32 wkh_openwave_x_up_proxy_trust(proto_tree *tree,
1513                 tvbuff_t *tvb, guint32 hdr_start);
1514 static guint32 wkh_openwave_x_up_devcap_has_color(proto_tree *tree,
1515                 tvbuff_t *tvb, guint32 hdr_start);
1516 static guint32 wkh_openwave_x_up_devcap_num_softkeys(proto_tree *tree,
1517                 tvbuff_t *tvb, guint32 hdr_start);
1518 static guint32 wkh_openwave_x_up_devcap_softkey_size(proto_tree *tree,
1519                 tvbuff_t *tvb, guint32 hdr_start);
1520 static guint32 wkh_openwave_x_up_devcap_screen_chars(proto_tree *tree,
1521                 tvbuff_t *tvb, guint32 hdr_start);
1522 static guint32 wkh_openwave_x_up_devcap_screen_pixels(proto_tree *tree,
1523                 tvbuff_t *tvb, guint32 hdr_start);
1524 static guint32 wkh_openwave_x_up_devcap_em_size(proto_tree *tree,
1525                 tvbuff_t *tvb, guint32 hdr_start);
1526 static guint32 wkh_openwave_x_up_devcap_screen_depth(proto_tree *tree,
1527                 tvbuff_t *tvb, guint32 hdr_start);
1528 static guint32 wkh_openwave_x_up_devcap_immed_alert(proto_tree *tree,
1529                 tvbuff_t *tvb, guint32 hdr_start);
1530 static guint32 wkh_openwave_x_up_devcap_gui(proto_tree *tree,
1531                 tvbuff_t *tvb, guint32 hdr_start);
1532
1533 static guint32 wkh_openwave_x_up_proxy_trans_charset(proto_tree *tree,
1534                 tvbuff_t *tvb, guint32 hdr_start);
1535 static guint32 wkh_openwave_x_up_proxy_push_accept(proto_tree *tree,
1536                 tvbuff_t *tvb, guint32 hdr_start);
1537
1538
1539 /* Define a pointer to function data type for the well-known header
1540  * lookup table below */
1541 typedef guint32 (*hdr_parse_func_ptr) (proto_tree *, tvbuff_t *, guint32);
1542
1543 /* Lookup table for well-known header parsing functions */
1544 static const hdr_parse_func_ptr WellKnownHeader[128] = {
1545         /* 0x00 */      wkh_accept,                             /* 0x01 */      wkh_accept_charset,
1546         /* 0x02 */      wkh_accept_encoding,    /* 0x03 */      wkh_accept_language,
1547         /* 0x04 */      wkh_accept_ranges,              /* 0x05 */      wkh_age,
1548         /* 0x06 */      wkh_allow,                              /* 0x07 */      wkh_authorization,
1549         /* 0x08 */      wkh_cache_control,              /* 0x09 */      wkh_connection,
1550         /* 0x0A */      wkh_content_base,               /* 0x0B */      wkh_content_encoding,
1551         /* 0x0C */      wkh_content_language,   /* 0x0D */      wkh_content_length,
1552         /* 0x0E */      wkh_content_location,   /* 0x0F */      wkh_content_md5,
1553         /* 0x10 */      wkh_content_range,              /* 0x11 */      wkh_content_type,
1554         /* 0x12 */      wkh_date,                               /* 0x13 */      wkh_etag,
1555         /* 0x14 */      wkh_expires,                    /* 0x15 */      wkh_from,
1556         /* 0x16 */      wkh_host,                               /* 0x17 */      wkh_if_modified_since,
1557         /* 0x18 */      wkh_if_match,                   /* 0x19 */      wkh_if_none_match,
1558         /* 0x1A */      wkh_if_range,                   /* 0x1B */      wkh_if_unmodified_since,
1559         /* 0x1C */      wkh_location,                   /* 0x1D */      wkh_last_modified,
1560         /* 0x1E */      wkh_max_forwards,               /* 0x1F */      wkh_pragma,
1561         /* 0x20 */      wkh_proxy_authenticate, /* 0x21 */      wkh_proxy_authorization,
1562         /* 0x22 */      wkh_public,                             /* 0x23 */      wkh_range,
1563         /* 0x24 */      wkh_referer,                    /* 0x25 */      wkh_default,
1564         /* 0x26 */      wkh_server,                             /* 0x27 */      wkh_transfer_encoding,
1565         /* 0x28 */      wkh_upgrade,                    /* 0x29 */      wkh_user_agent,
1566         /* 0x2A */      wkh_vary,                               /* 0x2B */      wkh_via,
1567         /* 0x2C */      wkh_warning,                    /* 0x2D */      wkh_www_authenticate,
1568         /* 0x2E */      wkh_content_disposition,/* 0x2F */      wkh_x_wap_application_id,
1569         /* 0x30 */      wkh_content_uri,                /* 0x31 */      wkh_initiator_uri,
1570         /* 0x32 */      wkh_accept_application, /* 0x33 */      wkh_bearer_indication,
1571         /* 0x34 */      wkh_push_flag,                  /* 0x35 */      wkh_profile,
1572         /* 0x36 */      wkh_default,                    /* 0x37 */      wkh_profile_warning,
1573         /* 0x38 */      wkh_default,                    /* 0x39 */      wkh_te,
1574         /* 0x3A */      wkh_trailer,                    /* 0x3B */      wkh_accept_charset,
1575         /* 0x3C */      wkh_accept_encoding,    /* 0x3D */      wkh_cache_control,
1576         /* 0x3E */      wkh_content_range,              /* 0x3F */      wkh_x_wap_tod,
1577         /* 0x40 */      wkh_content_id,                 /* 0x41 */      wkh_default,
1578         /* 0x42 */      wkh_default,                    /* 0x43 */      wkh_encoding_version,
1579         /* 0x44 */      wkh_profile_warning,    /* 0x45 */      wkh_content_disposition,
1580         /* 0x46 */      wkh_x_wap_security,             /* 0x47 */      wkh_cache_control,
1581         /*******************************************************
1582          *** The following headers are not (yet) registered. ***
1583          *******************************************************/
1584         /* 0x48 */      wkh_default,                    /* 0x49 */      wkh_default,
1585         /* 0x4A */      wkh_default,                    /* 0x4B */      wkh_default,
1586         /* 0x4C */      wkh_default,                    /* 0x4D */      wkh_default,
1587         /* 0x4E */      wkh_default,                    /* 0x4F */      wkh_default,
1588         /* 0x50 */      wkh_default,                    /* 0x51 */      wkh_default,
1589         /* 0x52 */      wkh_default,                    /* 0x53 */      wkh_default,
1590         /* 0x54 */      wkh_default,                    /* 0x55 */      wkh_default,
1591         /* 0x56 */      wkh_default,                    /* 0x57 */      wkh_default,
1592         /* 0x58 */      wkh_default,                    /* 0x59 */      wkh_default,
1593         /* 0x5A */      wkh_default,                    /* 0x5B */      wkh_default,
1594         /* 0x5C */      wkh_default,                    /* 0x5D */      wkh_default,
1595         /* 0x5E */      wkh_default,                    /* 0x5F */      wkh_default,
1596         /* 0x60 */      wkh_default,                    /* 0x61 */      wkh_default,
1597         /* 0x62 */      wkh_default,                    /* 0x63 */      wkh_default,
1598         /* 0x64 */      wkh_default,                    /* 0x65 */      wkh_default,
1599         /* 0x66 */      wkh_default,                    /* 0x67 */      wkh_default,
1600         /* 0x68 */      wkh_default,                    /* 0x69 */      wkh_default,
1601         /* 0x6A */      wkh_default,                    /* 0x6B */      wkh_default,
1602         /* 0x6C */      wkh_default,                    /* 0x6D */      wkh_default,
1603         /* 0x6E */      wkh_default,                    /* 0x6F */      wkh_default,
1604         /* 0x70 */      wkh_default,                    /* 0x71 */      wkh_default,
1605         /* 0x72 */      wkh_default,                    /* 0x73 */      wkh_default,
1606         /* 0x74 */      wkh_default,                    /* 0x75 */      wkh_default,
1607         /* 0x76 */      wkh_default,                    /* 0x77 */      wkh_default,
1608         /* 0x78 */      wkh_default,                    /* 0x79 */      wkh_default,
1609         /* 0x7A */      wkh_default,                    /* 0x7B */      wkh_default,
1610         /* 0x7C */      wkh_default,                    /* 0x7D */      wkh_default,
1611         /* 0x7E */      wkh_default,                    /* 0x7F */      wkh_default,
1612 }; 
1613
1614 /* Lookup table for well-known header parsing functions */
1615 static const hdr_parse_func_ptr WellKnownOpenwaveHeader[128] = {
1616         /* 0x00 */      wkh_openwave_default,
1617         /* 0x01 */      wkh_openwave_x_up_proxy_push_accept,
1618         /* 0x02 */      wkh_openwave_x_up_proxy_push_seq,
1619         /* 0x03 */      wkh_openwave_x_up_proxy_notify,
1620         /* 0x04 */      wkh_openwave_x_up_proxy_operator_domain,
1621         /* 0x05 */      wkh_openwave_x_up_proxy_home_page,
1622         /* 0x06 */      wkh_openwave_x_up_devcap_has_color,
1623         /* 0x07 */      wkh_openwave_x_up_devcap_num_softkeys,
1624         /* 0x08 */      wkh_openwave_x_up_devcap_softkey_size,
1625         /* 0x09 */      wkh_openwave_x_up_devcap_screen_chars,
1626         /* 0x0A */      wkh_openwave_x_up_devcap_screen_pixels,
1627         /* 0x0B */      wkh_openwave_x_up_devcap_em_size,
1628         /* 0x0C */      wkh_openwave_x_up_devcap_screen_depth,
1629         /* 0x0D */      wkh_openwave_x_up_devcap_immed_alert,
1630         /* 0x0E */      wkh_openwave_x_up_proxy_net_ask,
1631         /* 0x0F */      wkh_openwave_x_up_proxy_uplink_version,
1632         /* 0x10 */      wkh_openwave_x_up_proxy_tod,
1633         /* 0x11 */      wkh_openwave_x_up_proxy_ba_enable,
1634         /* 0x12 */      wkh_openwave_x_up_proxy_ba_realm,
1635         /* 0x13 */      wkh_openwave_x_up_proxy_redirect_enable,
1636         /* 0x14 */      wkh_openwave_x_up_proxy_request_uri,
1637         /* 0x15 */      wkh_openwave_x_up_proxy_redirect_status,
1638         /* 0x16 */      wkh_openwave_x_up_proxy_trans_charset,
1639         /* 0x17 */      wkh_openwave_x_up_proxy_linger,
1640         /* 0x18 */      wkh_openwave_default,
1641         /* 0x19 */      wkh_openwave_x_up_proxy_enable_trust,
1642         /* 0x1A */      wkh_openwave_x_up_proxy_trust,
1643         /* 0x1B */      wkh_openwave_default,
1644         /* 0x1C */      wkh_openwave_default,
1645         /* 0x1D */      wkh_openwave_default,
1646         /* 0x1E */      wkh_openwave_default,
1647         /* 0x1F */      wkh_openwave_default,
1648         /* 0x20 */      wkh_openwave_x_up_proxy_trust,
1649         /* 0x21 */      wkh_openwave_x_up_proxy_bookmark,
1650         /* 0x22 */      wkh_openwave_x_up_devcap_gui,
1651         /*******************************************************
1652          *** The following headers are not (yet) registered. ***
1653          *******************************************************/
1654         /* 0x23 */      wkh_openwave_default,
1655         /* 0x24 */      wkh_openwave_default,           /* 0x25 */      wkh_openwave_default,
1656         /* 0x26 */      wkh_openwave_default,           /* 0x27 */      wkh_openwave_default,
1657         /* 0x28 */      wkh_openwave_default,           /* 0x29 */      wkh_openwave_default,
1658         /* 0x2A */      wkh_openwave_default,           /* 0x2B */      wkh_openwave_default,
1659         /* 0x2C */      wkh_openwave_default,           /* 0x2D */      wkh_openwave_default,
1660         /* 0x2E */      wkh_openwave_default,           /* 0x2F */      wkh_openwave_default,
1661         /* 0x30 */      wkh_openwave_default,           /* 0x31 */      wkh_openwave_default,
1662         /* 0x32 */      wkh_openwave_default,           /* 0x33 */      wkh_openwave_default,
1663         /* 0x34 */      wkh_openwave_default,           /* 0x35 */      wkh_openwave_default,
1664         /* 0x36 */      wkh_openwave_default,           /* 0x37 */      wkh_openwave_default,
1665         /* 0x38 */      wkh_openwave_default,           /* 0x39 */      wkh_openwave_default,
1666         /* 0x3A */      wkh_openwave_default,           /* 0x3B */      wkh_openwave_default,
1667         /* 0x3C */      wkh_openwave_default,           /* 0x3D */      wkh_openwave_default,
1668         /* 0x3E */      wkh_openwave_default,           /* 0x3F */      wkh_openwave_default,
1669         /* 0x40 */      wkh_openwave_default,           /* 0x41 */      wkh_openwave_default,
1670         /* 0x42 */      wkh_openwave_default,           /* 0x43 */      wkh_openwave_default,
1671         /* 0x44 */      wkh_openwave_default,           /* 0x45 */      wkh_openwave_default,
1672         /* 0x46 */      wkh_openwave_default,           /* 0x47 */      wkh_openwave_default,
1673         /* 0x48 */      wkh_openwave_default,           /* 0x49 */      wkh_openwave_default,
1674         /* 0x4A */      wkh_openwave_default,           /* 0x4B */      wkh_openwave_default,
1675         /* 0x4C */      wkh_openwave_default,           /* 0x4D */      wkh_openwave_default,
1676         /* 0x4E */      wkh_openwave_default,           /* 0x4F */      wkh_openwave_default,
1677         /* 0x50 */      wkh_openwave_default,           /* 0x51 */      wkh_openwave_default,
1678         /* 0x52 */      wkh_openwave_default,           /* 0x53 */      wkh_openwave_default,
1679         /* 0x54 */      wkh_openwave_default,           /* 0x55 */      wkh_openwave_default,
1680         /* 0x56 */      wkh_openwave_default,           /* 0x57 */      wkh_openwave_default,
1681         /* 0x58 */      wkh_openwave_default,           /* 0x59 */      wkh_openwave_default,
1682         /* 0x5A */      wkh_openwave_default,           /* 0x5B */      wkh_openwave_default,
1683         /* 0x5C */      wkh_openwave_default,           /* 0x5D */      wkh_openwave_default,
1684         /* 0x5E */      wkh_openwave_default,           /* 0x5F */      wkh_openwave_default,
1685         /* 0x60 */      wkh_openwave_default,           /* 0x61 */      wkh_openwave_default,
1686         /* 0x62 */      wkh_openwave_default,           /* 0x63 */      wkh_openwave_default,
1687         /* 0x64 */      wkh_openwave_default,           /* 0x65 */      wkh_openwave_default,
1688         /* 0x66 */      wkh_openwave_default,           /* 0x67 */      wkh_openwave_default,
1689         /* 0x68 */      wkh_openwave_default,           /* 0x69 */      wkh_openwave_default,
1690         /* 0x6A */      wkh_openwave_default,           /* 0x6B */      wkh_openwave_default,
1691         /* 0x6C */      wkh_openwave_default,           /* 0x6D */      wkh_openwave_default,
1692         /* 0x6E */      wkh_openwave_default,           /* 0x6F */      wkh_openwave_default,
1693         /* 0x70 */      wkh_openwave_default,           /* 0x71 */      wkh_openwave_default,
1694         /* 0x72 */      wkh_openwave_default,           /* 0x73 */      wkh_openwave_default,
1695         /* 0x74 */      wkh_openwave_default,           /* 0x75 */      wkh_openwave_default,
1696         /* 0x76 */      wkh_openwave_default,           /* 0x77 */      wkh_openwave_default,
1697         /* 0x78 */      wkh_openwave_default,           /* 0x79 */      wkh_openwave_default,
1698         /* 0x7A */      wkh_openwave_default,           /* 0x7B */      wkh_openwave_default,
1699         /* 0x7C */      wkh_openwave_default,           /* 0x7D */      wkh_openwave_default,
1700         /* 0x7E */      wkh_openwave_default,           /* 0x7F */      wkh_openwave_default,
1701 }; 
1702
1703
1704
1705
1706
1707
1708 /* WSP header format
1709  *   1st byte: 0x00        : <Not allowed>
1710  *   1st byte: 0x01 -- 0x1F: <Shorthand Header Code Page switch>
1711  *   1st byte: 0x20 -- 0x7E: <Textual header (C string)>
1712  *       Followed with: <Textual header value (C string)>
1713  *   1st byte: 0x7F        : <Header Code Page switch>
1714  *       Followed with: 2nd byte: <Header Code Page>
1715  *   1st byte: 0x80 -- 0xFF: <Binary header (7-bit encoded ID)>
1716  *       Followed with:
1717  *         2nd byte: 0x00 -- 0x1E: <Value Length (bytes)>
1718  *             Followed with: <Len> bytes of data
1719  *         2nd byte: 0x1F        : <Value Length is a guintvar>
1720  *             Followed with: <guintvar Len>
1721  *             Followed with: <Len> bytes of data
1722  *         2nd byte: 0x20 -- 0x7F: <Textual header value (C string)>
1723  *         2nd byte: 0x80 -- 0xFF: <Binary value (7-bit encoded ID)>
1724  */
1725 static void
1726 add_headers (proto_tree *tree, tvbuff_t *tvb, int hf)
1727 {
1728         guint8 hdr_id, val_id, codepage = 1;
1729         gint32 tvb_len = tvb_length(tvb);
1730         gint32 offset = 0, hdr_len, hdr_start;
1731         gint32 val_len, val_start;
1732         guint8 *hdr_str, *val_str;
1733         proto_tree *wsp_headers;
1734         proto_item *ti;
1735         guint8 ok;
1736         guint32 val = 0;
1737         nstime_t tv;
1738
1739         if (offset >= tvb_len)
1740                 return; /* No headers! */
1741
1742         ti = proto_tree_add_item(tree, hf,
1743                         tvb, offset, tvb_len, bo_little_endian);
1744         wsp_headers = proto_item_add_subtree(ti, ett_headers);
1745
1746         while (offset < tvb_len) {
1747                 hdr_start = offset;
1748                 hdr_id = tvb_get_guint8(tvb, offset);
1749                 if (hdr_id & 0x80) { /* Well-known header */
1750                         hdr_len = 1;
1751                         val_start = ++offset;
1752                         val_id = tvb_get_guint8(tvb, val_start);
1753                         /* Call header value dissector for given header */
1754                         if (codepage == 1) { /* Default header code page */
1755                                 DebugLog(("add_headers(code page 0): %s\n",
1756                                                         match_strval (hdr_id & 0x7f, vals_field_names)));
1757                                 offset = WellKnownHeader[hdr_id & 0x7F](wsp_headers, tvb,
1758                                                 hdr_start);
1759                         } else { /* Openwave header code page */
1760                                 /* Here I'm delibarately assuming that Openwave is the only
1761                                  * company that defines a WSP header code page. */
1762                                 DebugLog(("add_headers(code page 0x%02x - assumed to be x-up-1): %s\n",
1763                                                         codepage, match_strval (hdr_id & 0x7f, vals_openwave_field_names)));
1764                                 offset = WellKnownOpenwaveHeader[hdr_id & 0x7F](wsp_headers,
1765                                                 tvb, hdr_start);
1766                         }
1767                 } else if (hdr_id == 0x7F) { /* HCP shift sequence */
1768                         codepage = tvb_get_guint8(tvb, offset+1);
1769                         proto_tree_add_uint(wsp_headers, hf_wsp_header_shift_code,
1770                                         tvb, offset, 2, codepage);
1771                         offset += 2;
1772                 } else if (hdr_id >= 0x20) { /* Textual header */
1773                         /* Header name MUST be NUL-ended string ==> tvb_get_stringz() */
1774                         hdr_str = tvb_get_stringz(tvb, hdr_start, &hdr_len);
1775                         val_start = hdr_start + hdr_len;
1776                         val_id = tvb_get_guint8(tvb, val_start);
1777                         /* Call header value dissector for given header */
1778                         if (val_id >= 0x20 && val_id <=0x7E) { /* OK! */
1779                                 val_str = tvb_get_stringz(tvb, val_start, &val_len);
1780                                 g_assert(val_str);
1781                                 offset = val_start + val_len;
1782                                 proto_tree_add_text(wsp_headers,tvb,hdr_start,offset-hdr_start,
1783                                                 "%s: %s", hdr_str, val_str);
1784                                 g_free (val_str);
1785                         } else {
1786                                 /* Old-style X-WAP-TOD uses a non-textual value
1787                                  * after a textual header. */
1788                                 if (strcasecmp(hdr_str, "x-wap.tod") == 0) {
1789                                         get_delta_seconds_value(val, tvb, val_start, val_len, ok);
1790                                         if (ok) {
1791                                                 if (val == 0) {
1792                                                         ti = proto_tree_add_string (wsp_headers,
1793                                                                         hf_hdr_x_wap_tod,
1794                                                                         tvb, hdr_start, hdr_len + val_len,
1795                                                                         "Requesting Time Of Day");
1796                                                 } else {
1797                                                         tv.secs = val;
1798                                                         tv.nsecs = 0;
1799                                                         val_str = abs_time_to_str(&tv);
1800                                                         g_assert (val_str);
1801                                                         ti = proto_tree_add_string (wsp_headers,
1802                                                                         hf_hdr_x_wap_tod,
1803                                                                         tvb, hdr_start, hdr_len + val_len, val_str);
1804                                                 }
1805                                                 proto_item_append_text(ti, " <Warning: "
1806                                                                 "should be encoded as a textual value>");
1807                                         } else {
1808                                                 /* I prefer using X-Wap-Tod to the real hdr_str */
1809                                                 proto_tree_add_string (wsp_headers, hf_hdr_x_wap_tod,
1810                                                                 tvb, hdr_start, hdr_len + val_len,
1811                                                                 InvalidValueForHeader("X-Wap-Tod"));
1812                                         }
1813                                 } else {
1814                                         proto_tree_add_text (wsp_headers, tvb, hdr_start, hdr_len,
1815                                                         "<Error: Invalid value for the textual '%s' header"
1816                                                         " (should be a textual value)>",
1817                                                         hdr_str);
1818                                 }
1819                                 offset = tvb_len;
1820                         }
1821                         proto_tree_add_string_hidden(wsp_headers, hf_hdr_name,
1822                                         tvb, hdr_start, offset - hdr_start, hdr_str);
1823                 } else if (hdr_id > 0) { /* Shorthand HCP switch */
1824                         codepage = hdr_id;
1825                         proto_tree_add_uint (wsp_headers, hf_wsp_header_shift_code,
1826                                         tvb, offset, 1, codepage);
1827                         offset++;
1828                 } else {
1829                         proto_tree_add_text (wsp_headers, tvb, hdr_start, 1,
1830                                         InvalidTextualHeader);
1831                         offset = tvb_len;
1832                 }
1833         }
1834 }
1835
1836
1837 /* The following macros hide common processing for all well-known headers
1838  * and shortens the code to be written in a wkh_XXX() function.
1839  * Even declarations are hidden by a macro.
1840  *
1841  * Define a wkh_XXX() function as follows:
1842  *
1843  * static guint32
1844  * wkh_XXX (proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
1845  * {
1846  *              wkh_0_Declarations;
1847  *              << add other required declarations here >>
1848  *
1849  *              wkh_1_WellKnownValue;
1850  *                      << add well-known value proto item here; don't forget to set the
1851  *                      ok variable to TRUE if parsing was correct >>
1852  *              wkh_2_TextualValue;
1853  *                      << add textual value proto item here; don't forget to set the
1854  *                      ok variable to TRUE if parsing was correct >>
1855  *              wkh_3_ValueWithLength;
1856  *                      << add custom code for value processing and value proto item here >>
1857  *
1858  *              wkh_4_End(hf);
1859  *                      << This macro takes care of parse errors within the header value;
1860  *                      it requires the header field index if the header has not yet been
1861  *                      written to the protocol tree (ti == NULL). >>
1862  * }
1863  *
1864  *      NOTE:   You only need to write parsing code for the successful case,
1865  *                      Errors are automatically reported through the wkh_4_End() macro
1866  *                      when ok <> TRUE.
1867  */
1868
1869 /* The following code is the generic template with which the value of a
1870  * well-known header can be processed. Not all sections yield a semantically
1871  * correct result, so appropriate error information must be provided.
1872  */
1873
1874
1875 #define wkh_0_Declarations                                      /* Declarations for Parsing */ \
1876         gboolean ok = FALSE; /* Triggers error notification code at end */ \
1877         proto_item *ti = NULL; /* Needed for error notification at end */ \
1878         guint32 val_start = hdr_start + 1; \
1879         guint8 hdr_id = tvb_get_guint8 (tvb, hdr_start) & 0x7F; \
1880         guint8 val_id = tvb_get_guint8 (tvb, val_start); \
1881         guint32 offset = val_start; /* Offset to one past this header */ \
1882         guint32 val_len; /* length for value with length field */ \
1883         guint32 val_len_len; /* length of length field */ \
1884         guint8 *val_str = NULL
1885
1886 #define wkh_1_WellKnownValue                            /* Parse Well Known Value */ \
1887         proto_tree_add_string_hidden(tree, hf_hdr_name, \
1888                         tvb, hdr_start, offset - hdr_start, \
1889                         val_to_str (hdr_id, vals_field_names, \
1890                                 "<Unknown WSP header field 0x%02X>")); \
1891         if (val_id & 0x80) { /* Well-known value */ \
1892                 offset++; \
1893                 /* Well-known value processing starts HERE \
1894                  * \
1895                  * BEGIN */
1896
1897 #define wkh_2_TextualValue                                      /* Parse Textual Value */ \
1898                 /* END */ \
1899         } else if ((val_id == 0) || (val_id >= 0x20)) { /* Textual value */ \
1900                 val_str = tvb_get_stringz (tvb, val_start, &val_len); \
1901                 g_assert(val_str); \
1902                 offset = val_start + val_len; \
1903                 /* Textual value processing starts HERE \
1904                  * \
1905                  * BEGIN */
1906
1907 #define wkh_3_ValueWithLength                           /* Parse Value With Length */ \
1908                 /* END */ \
1909                 g_free(val_str); \
1910         } else { /* val_start points to 1st byte of length field */ \
1911                 if (val_id == 0x1F) { /* Value Length = guintvar */ \
1912                         val_len = tvb_get_guintvar(tvb, val_start + 1, &val_len_len); \
1913                         val_len_len++; /* 0x1F length indicator byte */ \
1914                 } else { /* Short length followed by Len data octets */ \
1915                         val_len = tvb_get_guint8(tvb, offset); \
1916                         val_len_len = 1; \
1917                 } \
1918                 offset += val_len_len + val_len; \
1919                 /* Value with length processing starts HERE \
1920                  * The value lies between val_start and offset: \
1921                  *  - Value Length:     Start  = val_start \
1922                  *                                      Length = val_len_len \
1923                  *  - Value Data  :     Start  = val_start + val_len_len \
1924                  *                                      Length = val_len \
1925                  *                                      End    = offset - 1 \
1926                  * BEGIN */
1927
1928 #define wkh_4_End(hf)                                           /* End of value parsing */ \
1929                 /* END */ \
1930         } \
1931         /* Check for errors */ \
1932         if (! ok) { \
1933                 if (ti) { /* Append to protocol tree item label */ \
1934                         proto_item_append_text(ti, \
1935                                         " <Error: Invalid header value>"); \
1936                 } else if (hf > 0) { /* Create protocol tree item */ \
1937                         proto_tree_add_string(tree, hf, \
1938                                         tvb, hdr_start, offset - hdr_start, \
1939                                         " <Error: Invalid header value>"); \
1940                 } else { /* Create anonymous header field entry */ \
1941                         proto_tree_add_text(tree, tvb, hdr_start, offset - hdr_start, \
1942                                         "%s: <Error: Invalid header value>", \
1943                                         val_to_str (hdr_id, vals_field_names, \
1944                                                 "<Unknown WSP header field 0x%02X>")); \
1945                 } \
1946         } \
1947         return offset;
1948
1949
1950 /*
1951  * This yields the following default header value parser function body
1952  */
1953 static guint32
1954 wkh_default(proto_tree *tree, tvbuff_t *tvb,
1955                 guint32 hdr_start)
1956 {
1957         wkh_0_Declarations;
1958
1959         ok = TRUE; /* Bypass error checking as we don't parse the values! */
1960
1961         wkh_1_WellKnownValue;
1962                 ti = proto_tree_add_text (tree, tvb, hdr_start, offset - hdr_start,
1963                                 "%s: (Undecoded well-known value 0x%02x)",
1964                                 val_to_str (hdr_id, vals_field_names,
1965                                         "<Unknown WSP header field 0x%02X>"), val_id & 0x7F);
1966         wkh_2_TextualValue;
1967                 ti = proto_tree_add_text(tree, tvb, hdr_start, offset - hdr_start,
1968                                 "%s: %s",
1969                                 val_to_str (hdr_id, vals_field_names,
1970                                         "<Unknown WSP header field 0x%02X>"), val_str);
1971         wkh_3_ValueWithLength;
1972                 ti = proto_tree_add_text (tree, tvb, hdr_start, offset - hdr_start,
1973                                 "%s: (Undecoded value in general form with length indicator)",
1974                                 val_to_str (hdr_id, vals_field_names,
1975                                         "<Unknown WSP header field 0x%02X>"));
1976
1977         wkh_4_End(HF_EMPTY); /* The default parser has no associated hf_index;
1978                                                         additionally the error code is always bypassed */
1979 }
1980
1981
1982 /* Content-type processing uses the following common core: */
1983 #define wkh_content_type_header(underscored,Text) \
1984 static guint32 \
1985 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
1986 { \
1987         wkh_0_Declarations; \
1988         guint32 off, val = 0, len; \
1989         guint8 peek; \
1990         proto_tree *parameter_tree = NULL; \
1991         \
1992         wkh_1_WellKnownValue; \
1993                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
1994                                 tvb, hdr_start, offset - hdr_start, \
1995                                 val_to_str(val_id & 0x7F, vals_content_types, \
1996                                         "(Unknown content type identifier 0x%X)")); \
1997                 ok = TRUE; \
1998         wkh_2_TextualValue; \
1999                 /* Sometimes with a No-Content response, a NULL content type \
2000                  * is reported. Process this correctly! */ \
2001                 if (*val_str) { \
2002                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2003                                         tvb, hdr_start, offset - hdr_start, \
2004                                         val_str); \
2005                 } else { \
2006                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2007                                         tvb, hdr_start, offset - hdr_start, \
2008                                         "<no content type has been specified>"); \
2009                 } \
2010                 ok = TRUE; \
2011         wkh_3_ValueWithLength; \
2012                 off = val_start + val_len_len; \
2013                 peek = tvb_get_guint8(tvb, off); \
2014                 if (is_text_string(peek)) { \
2015                         get_extension_media(val_str, tvb, off, len, ok); \
2016                         /* As we're using val_str, it is automatically g_free()d */ \
2017                         off += len; /* off now points to 1st byte after string */ \
2018                         ti = proto_tree_add_string (tree, hf_hdr_ ## underscored, \
2019                                         tvb, hdr_start, offset - hdr_start, val_str); \
2020                 } else if (is_integer_value(peek)) { \
2021                         get_integer_value(val, tvb, off, len, ok); \
2022                         if (ok) { \
2023                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2024                                                 tvb, hdr_start, offset - hdr_start, \
2025                                                 val_to_str(val, vals_content_types, \
2026                                                         "(Unknown content type identifier 0x%X)")); \
2027                         } \
2028                         off += len; \
2029                 } \
2030                 /* Remember: offset == val_start + val_len + val_len_len */ \
2031                 if (ok && (off < offset)) { /* Add parameters if any */ \
2032                         parameter_tree = proto_item_add_subtree (ti, ett_header); \
2033                         while (off < offset) { \
2034                                 off = parameter (parameter_tree, ti, tvb, off, offset - off); \
2035                         } \
2036                 } \
2037         \
2038         wkh_4_End(hf_hdr_ ## underscored); \
2039 }
2040
2041
2042 /*
2043  * Accept-value =
2044  *        Short-integer
2045  *      | Extension-media
2046  *      | ( Value-length ( Extension-media | Integer-value ) *( Parameter ) )
2047  */
2048 wkh_content_type_header(accept, "Accept")
2049
2050
2051 /*
2052  * Content-type-value =
2053  *        Short-integer
2054  *      | Extension-media
2055  *      | ( Value-length ( Extension-media | Integer-value ) *( Parameter ) )
2056  *
2057  * Beware: this header should not appear as such; it is dissected elsewhere
2058  * and at the same time the content type is used for subdissectors.
2059  * It is here for the sake of completeness.
2060  */
2061 wkh_content_type_header(content_type, "Content-Type")
2062
2063
2064 /*
2065  * Content-type-value =
2066  *        Short-integer
2067  *      | Extension-media
2068  *      | ( Value-length ( Extension-media | Integer-value ) *( Parameter ) )
2069  *
2070  * This function adds the content type value to the protocol tree,
2071  * and computes either the numeric or textual media type in return,
2072  * which will be used for further subdissection (e.g., MMS, WBXML).
2073  */
2074 guint32
2075 add_content_type(proto_tree *tree, tvbuff_t *tvb, guint32 val_start,
2076                 guint32 *well_known_content, const char **textual_content)
2077 {
2078         /* Replace wkh_0_Declarations with slightly modified declarations
2079          * so we can still make use of the wkh_[1-4]_XXX macros! */
2080         guint32 hdr_start = val_start; /* No header name, only value! */
2081         guint8 hdr_id = FN_CONTENT_TYPE; /* Same remark */
2082         guint8 val_id = tvb_get_guint8 (tvb, val_start);
2083         guint32 offset = val_start; /* Offset to one past this header */
2084         guint32 val_len; /* length for value with length field */
2085         guint32 val_len_len; /* length of length field */
2086         guint8 *val_str = NULL;
2087         guint32 off, val = 0, len;
2088         guint8 peek;
2089         gboolean ok = FALSE;
2090         proto_item *ti = NULL;
2091         proto_tree *parameter_tree = NULL;
2092
2093         *textual_content = NULL;
2094         *well_known_content = 0;
2095
2096         DebugLog(("add_content_type() - START\n"));
2097
2098         wkh_1_WellKnownValue;
2099                 DebugLog(("add_content_type() - Well-known - Start\n"));
2100                 *textual_content = val_to_str(val_id & 0x7F, vals_content_types,
2101                                 "<Unknown media type identifier 0x%X>");
2102                 ti = proto_tree_add_string(tree, hf_hdr_content_type,
2103                                 tvb, hdr_start, offset - hdr_start,
2104                                 *textual_content);
2105                 *well_known_content = val_id & 0x7F;
2106                 ok = TRUE;
2107                 DebugLog(("add_content_type() - Well-known - End\n"));
2108         wkh_2_TextualValue;
2109                 DebugLog(("add_content_type() - Textual - Start\n"));
2110                 /* Sometimes with a No-Content response, a NULL content type
2111                  * is reported. Process this correctly! */
2112                 if (*val_str) {
2113                         ti = proto_tree_add_string(tree, hf_hdr_content_type,
2114                                         tvb, hdr_start, offset - hdr_start,
2115                                         val_str);
2116                         /* As we're using val_str, it is automatically g_free()d */
2117                         *textual_content = g_strdup(val_str);
2118                         *well_known_content = 0;
2119                 } else {
2120                         ti = proto_tree_add_string(tree, hf_hdr_content_type,
2121                                         tvb, hdr_start, offset - hdr_start,
2122                                         "<no media type has been specified>");
2123                         *textual_content = NULL;
2124                         *well_known_content = 0;
2125                 }
2126                 ok = TRUE;
2127                 DebugLog(("add_content_type() - Textual - End\n"));
2128         wkh_3_ValueWithLength;
2129                 DebugLog(("add_content_type() - General form - Start\n"));
2130                 off = val_start + val_len_len;
2131                 peek = tvb_get_guint8(tvb, off);
2132                 if (is_text_string(peek)) {
2133                         DebugLog(("add_content_type() - General form - extension-media\n"));
2134                         get_extension_media(val_str, tvb, off, len, ok);
2135                         /* As we're using val_str, it is automatically g_free()d */
2136                         /* ??? Not sure anymore, we're in wkh_3, not in wkh_2 ! */
2137                         off += len; /* off now points to 1st byte after string */
2138                         ti = proto_tree_add_string (tree, hf_hdr_content_type,
2139                                         tvb, hdr_start, offset - hdr_start, val_str);
2140                         /* Following statement: required? */
2141                         *textual_content = g_strdup(val_str);
2142                         *well_known_content = 0;
2143                 } else if (is_integer_value(peek)) {
2144                         DebugLog(("add_content_type() - General form - integer_value\n"));
2145                         get_integer_value(val, tvb, off, len, ok);
2146                         if (ok) {
2147                                 *textual_content = val_to_str(val, vals_content_types,
2148                                                 "<Unknown media type identifier 0x%X>");
2149                                 ti = proto_tree_add_string(tree, hf_hdr_content_type,
2150                                                 tvb, hdr_start, offset - hdr_start,
2151                                                 *textual_content);
2152                                 *well_known_content = val;
2153                         }
2154                         off += len;
2155                 } /* else ok = FALSE */
2156                 /* Remember: offset == val_start + val_len_len + val_len */
2157                 if (ok && (off < offset)) { /* Add parameters if any */
2158                         DebugLog(("add_content_type() - General form - parameters\n"));
2159                         parameter_tree = proto_item_add_subtree (ti, ett_header);
2160                         while (off < offset) {
2161                                 DebugLog(("add_content_type() - General form - parameter start "
2162                                                         "(off = %u)\n", off));
2163                                 off = parameter (parameter_tree, ti, tvb, off, offset - off);
2164                                 DebugLog(("add_content_type() - General form - parameter end "
2165                                                         "(off = %u)\n", off));
2166                         }
2167                 }
2168                 DebugLog(("add_content_type() - General form - End\n"));
2169
2170         wkh_4_End(hf_hdr_content_type);
2171 }
2172
2173
2174 /*
2175  * Template for accept_X headers with optional Q parameter value
2176  */
2177 #define wkh_accept_x_q_header(underscored,Text,valueString,valueName) \
2178 static guint32 \
2179 wkh_ ## underscored (proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2180 { \
2181         wkh_0_Declarations; \
2182         guint32 off, val = 0, len; \
2183         guint8 peek; \
2184         proto_tree *parameter_tree = NULL; \
2185         \
2186         wkh_1_WellKnownValue; \
2187                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2188                                 tvb, hdr_start, offset - hdr_start, \
2189                                 val_to_str(val_id & 0x7F, valueString, \
2190                                         "<Unknown " valueName " identifier 0x%X>")); \
2191                 ok = TRUE; \
2192         wkh_2_TextualValue; \
2193                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2194                                 tvb, hdr_start, offset - hdr_start, val_str); \
2195                 ok = TRUE; \
2196         wkh_3_ValueWithLength; \
2197                 off = val_start + val_len_len; \
2198                 peek = tvb_get_guint8(tvb, off); \
2199                 if (is_text_string(peek)) { \
2200                         get_token_text(val_str, tvb, off, len, ok); \
2201                         /* As we're using val_str, it is automatically g_free()d */ \
2202                         off += len; /* off now points to 1st byte after string */ \
2203                         ti = proto_tree_add_string (tree, hf_hdr_ ## underscored, \
2204                                         tvb, hdr_start, offset - hdr_start, val_str); \
2205                 } else if (is_integer_value(peek)) { \
2206                         get_integer_value(val, tvb, off, len, ok); \
2207                         if (ok) { \
2208                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2209                                                 tvb, hdr_start, offset - hdr_start, \
2210                                                 val_to_str(val, valueString, \
2211                                                         "<Unknown " valueName " identifier 0x%X>")); \
2212                         } \
2213                         off += len; \
2214                 } /* else ok = FALSE */ \
2215                 /* Remember: offset == val_start + val_len */ \
2216                 if (ok && (off < offset)) { /* Add Q-value if available */ \
2217                         parameter_tree = proto_item_add_subtree (ti, ett_header); \
2218                         off = parameter_value_q (parameter_tree, ti, tvb, off); \
2219                 } \
2220         \
2221         wkh_4_End(hf_hdr_ ## underscored); \
2222 }
2223
2224 /*
2225  * Accept-charset-value =
2226  *        Short-integer
2227  *      | Extension-media
2228  *      | ( Value-length ( Token-text | Integer-value ) [ Q-value ] )
2229  */
2230 wkh_accept_x_q_header(accept_charset, "Accept-Charset",
2231                 vals_character_sets, "character set")
2232 /*
2233  * Accept-language-value =
2234  *        Short-integer
2235  *      | Extension-media
2236  *      | ( Value-length ( Text-string | Integer-value ) [ Q-value ] )
2237  */
2238 wkh_accept_x_q_header(accept_language, "Accept-Language",
2239                 vals_languages, "language")
2240
2241
2242 /*
2243  * Push-flag-value = Short-integer
2244  */
2245 static guint32
2246 wkh_push_flag(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2247 {
2248         wkh_0_Declarations;
2249         proto_tree *subtree = NULL;
2250
2251         wkh_1_WellKnownValue;
2252                 ti = proto_tree_add_string(tree, hf_hdr_push_flag,
2253                                 tvb, hdr_start, offset - hdr_start, "");
2254                 subtree = proto_item_add_subtree(ti, ett_header);
2255                 proto_tree_add_uint(subtree, hf_hdr_push_flag_auth,
2256                                 tvb, val_start, 1, val_id);
2257                 proto_tree_add_uint(subtree, hf_hdr_push_flag_trust,
2258                                 tvb, val_start, 1, val_id);
2259                 proto_tree_add_uint(subtree, hf_hdr_push_flag_last,
2260                                 tvb, val_start, 1, val_id);
2261                 if (val_id & 0x01)
2262                         proto_item_append_string(ti, " (Initiator URI authenticated)");
2263                 if (val_id & 0x02)
2264                         proto_item_append_string(ti, " (Content trusted)");
2265                 if (val_id & 0x04)
2266                         proto_item_append_string(ti, " (Last push message)");
2267                 if (val_id & 0x78)
2268                         proto_item_append_text(ti, " <Warning: Reserved flags set>");
2269                 else
2270                         ok = TRUE;
2271         wkh_2_TextualValue;
2272                 /* Invalid */
2273         wkh_3_ValueWithLength;
2274                 /* Invalid */
2275         wkh_4_End(hf_hdr_push_flag);
2276 }
2277
2278
2279 /*
2280  * Allow-value =
2281  *     Short-integer
2282  */
2283 static guint32
2284 wkh_allow(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2285 {
2286         wkh_0_Declarations;
2287
2288         wkh_1_WellKnownValue;
2289                 val_id &= 0x7F;
2290                 if (val_id >= 0x40) { /* Valid WSP method */
2291                         ti = proto_tree_add_string(tree, hf_hdr_allow,
2292                                         tvb, hdr_start, offset - hdr_start,
2293                                         val_to_str(val_id & 0x7F, vals_pdu_type,
2294                                                 "<Unknown WSP method 0x%02X>"));
2295                         ok = TRUE;
2296                 }
2297         wkh_2_TextualValue;
2298                 /* Invalid */
2299         wkh_3_ValueWithLength;
2300                 /* Invalid */
2301         wkh_4_End(hf_hdr_allow);
2302 }
2303
2304
2305 /*
2306  * Public-value =
2307  *     Token-text | Short-integer
2308  */
2309 static guint32
2310 wkh_public(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2311 {
2312         wkh_0_Declarations;
2313
2314         wkh_1_WellKnownValue;
2315                 val_id &= 0x7F;
2316                 if (val_id >= 0x40) { /* Valid WSP method */
2317                         ti = proto_tree_add_string(tree, hf_hdr_public,
2318                                         tvb, hdr_start, offset - hdr_start,
2319                                         val_to_str(val_id & 0x7F, vals_pdu_type,
2320                                                 "<Unknown WSP method 0x%02X>"));
2321                         ok = TRUE;
2322                 }
2323         wkh_2_TextualValue;
2324                 ti = proto_tree_add_string(tree, hf_hdr_public,
2325                                 tvb, hdr_start, offset - hdr_start, val_str);
2326                 ok = TRUE;
2327         wkh_3_ValueWithLength;
2328                 /* Invalid */
2329         wkh_4_End(hf_hdr_public);
2330 }
2331
2332
2333 /*
2334  * Vary-value =
2335  *     Token-text | Short-integer
2336  */
2337 static guint32
2338 wkh_vary(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2339 {
2340         wkh_0_Declarations;
2341
2342         wkh_1_WellKnownValue;
2343                 ti = proto_tree_add_string(tree, hf_hdr_vary,
2344                                 tvb, hdr_start, offset - hdr_start,
2345                                 val_to_str(val_id & 0x7F, vals_field_names,
2346                                         "<Unknown WSP header field 0x%02X>"));
2347                 ok = TRUE;
2348         wkh_2_TextualValue;
2349                 ti = proto_tree_add_string(tree, hf_hdr_vary,
2350                                 tvb, hdr_start, offset - hdr_start,
2351                                 val_str);
2352                 ok = TRUE;
2353         wkh_3_ValueWithLength;
2354                 /* Invalid */
2355         wkh_4_End(hf_hdr_vary);
2356 }
2357
2358
2359 /*
2360  * X-wap-security-value = 0x80
2361  */
2362 static guint32
2363 wkh_x_wap_security(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2364 {
2365         wkh_0_Declarations;
2366
2367         wkh_1_WellKnownValue;
2368                 if (val_id == 0x80) {
2369                         ti = proto_tree_add_string(tree, hf_hdr_x_wap_security,
2370                                         tvb, hdr_start, offset - hdr_start, "close-subordinate");
2371                         ok = TRUE;
2372                 }
2373         wkh_2_TextualValue;
2374                 /* Invalid */
2375         wkh_3_ValueWithLength;
2376                 /* Invalid */
2377         wkh_4_End(hf_hdr_x_wap_security);
2378 }
2379
2380
2381 /*
2382  * Connection-value = 0x80 | Token-text
2383  */
2384 static guint32
2385 wkh_connection(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2386 {
2387         wkh_0_Declarations;
2388
2389         wkh_1_WellKnownValue;
2390                 if (val_id == 0x80) {
2391                         ti = proto_tree_add_string(tree, hf_hdr_connection,
2392                                         tvb, hdr_start, offset - hdr_start, "close");
2393                         ok = TRUE;
2394                 }
2395         wkh_2_TextualValue;
2396                 ti = proto_tree_add_string(tree, hf_hdr_connection,
2397                                 tvb, hdr_start, offset - hdr_start, val_str);
2398                 ok = TRUE;
2399         wkh_3_ValueWithLength;
2400                 /* Invalid */
2401         wkh_4_End(hf_hdr_connection);
2402 }
2403
2404
2405 /*
2406  * Transfer-encoding-value = 0x80 | Token-text
2407  */
2408 static guint32
2409 wkh_transfer_encoding(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2410 {
2411         wkh_0_Declarations;
2412
2413         wkh_1_WellKnownValue;
2414                 if (val_id == 0x80) {
2415                         ti = proto_tree_add_string(tree, hf_hdr_transfer_encoding,
2416                                         tvb, hdr_start, offset - hdr_start, "chunked");
2417                         ok = TRUE;
2418                 }
2419         wkh_2_TextualValue;
2420                 ti = proto_tree_add_string(tree, hf_hdr_transfer_encoding,
2421                                 tvb, hdr_start, offset - hdr_start, val_str);
2422                 ok = TRUE;
2423         wkh_3_ValueWithLength;
2424                 /* Invalid */
2425         wkh_4_End(hf_hdr_transfer_encoding);
2426 }
2427
2428
2429 /*
2430  * Accept-range-value = 0x80 | 0x81 | Token-text
2431  */
2432 static guint32
2433 wkh_accept_ranges(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2434 {
2435         wkh_0_Declarations;
2436
2437         wkh_1_WellKnownValue;
2438                 switch (val_id) {
2439                         case 0x80: /* none */
2440                                 ti = proto_tree_add_string(tree, hf_hdr_accept_ranges,
2441                                                 tvb, hdr_start, offset - hdr_start, "none");
2442                                 ok = TRUE;
2443                                 break;
2444                         case 0x81: /* bytes */
2445                                 ti = proto_tree_add_string(tree, hf_hdr_accept_ranges,
2446                                                 tvb, hdr_start, offset - hdr_start, "bytes");
2447                                 ok = TRUE;
2448                                 break;
2449                 }
2450         wkh_2_TextualValue;
2451                 ti = proto_tree_add_string(tree, hf_hdr_accept_ranges,
2452                                 tvb, hdr_start, offset - hdr_start, val_str);
2453                 ok = TRUE;
2454         wkh_3_ValueWithLength;
2455                 /* Invalid */
2456         wkh_4_End(hf_hdr_accept_ranges);
2457 }
2458
2459
2460 /*
2461  * Content-encoding-value = 0x80 | 0x81 | 0x82 | Token-text
2462  */
2463 static guint32
2464 wkh_content_encoding(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2465 {
2466         wkh_0_Declarations;
2467
2468         wkh_1_WellKnownValue;
2469                 switch (val_id) {
2470                         case 0x80: /* gzip */
2471                                 ti = proto_tree_add_string(tree, hf_hdr_content_encoding,
2472                                                 tvb, hdr_start, offset - hdr_start, "gzip");
2473                                 ok = TRUE;
2474                                 break;
2475                         case 0x81: /* compress */
2476                                 ti = proto_tree_add_string(tree, hf_hdr_content_encoding,
2477                                                 tvb, hdr_start, offset - hdr_start, "compress");
2478                                 ok = TRUE;
2479                                 break;
2480                         case 0x82: /* deflate */
2481                                 ti = proto_tree_add_string(tree, hf_hdr_content_encoding,
2482                                                 tvb, hdr_start, offset - hdr_start, "deflate");
2483                                 ok = TRUE;
2484                                 break;
2485                 }
2486         wkh_2_TextualValue;
2487                 ti = proto_tree_add_string(tree, hf_hdr_content_encoding,
2488                                 tvb, hdr_start, offset - hdr_start, val_str);
2489                 ok = TRUE;
2490         wkh_3_ValueWithLength;
2491                 /* Invalid */
2492         wkh_4_End(hf_hdr_content_encoding);
2493 }
2494
2495
2496 /*
2497  * Accept-encoding-value =
2498  *        Short-integer
2499  *      | Token-text
2500  *      | ( Value-length ( Short-integer | Text-string ) [ Q-value ] )
2501  */
2502 static guint32
2503 wkh_accept_encoding(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2504 {
2505         wkh_0_Declarations;
2506         guint32 len, off;
2507         guint8 peek;
2508         gchar *str;
2509         proto_tree *parameter_tree = NULL;
2510
2511         wkh_1_WellKnownValue;
2512                 switch (val_id) {
2513                         case 0x80: /* gzip */
2514                                 ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2515                                                 tvb, hdr_start, offset - hdr_start, "gzip");
2516                                 ok = TRUE;
2517                                 break;
2518                         case 0x81: /* compress */
2519                                 ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2520                                                 tvb, hdr_start, offset - hdr_start, "compress");
2521                                 ok = TRUE;
2522                                 break;
2523                         case 0x82: /* deflate */
2524                                 ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2525                                                 tvb, hdr_start, offset - hdr_start, "deflate");
2526                                 ok = TRUE;
2527                                 break;
2528                 }
2529         wkh_2_TextualValue;
2530                 proto_tree_add_string(tree, hf_hdr_accept_encoding,
2531                                 tvb, hdr_start, offset - hdr_start, val_str);
2532                 ok = TRUE;
2533         wkh_3_ValueWithLength;
2534                 off = val_start + val_len_len;
2535                 peek = tvb_get_guint8(tvb, off);
2536                 if (is_short_integer(peek)) {
2537                         switch (val_id) {
2538                                 case 0x80: /* gzip */
2539                                         ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2540                                                         tvb, hdr_start, offset - hdr_start, "gzip");
2541                                         ok = TRUE;
2542                                         break;
2543                                 case 0x81: /* compress */
2544                                         ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2545                                                         tvb, hdr_start, offset - hdr_start, "compress");
2546                                         ok = TRUE;
2547                                         break;
2548                                 case 0x82: /* deflate */
2549                                         ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2550                                                         tvb, hdr_start, offset - hdr_start, "deflate");
2551                                         ok = TRUE;
2552                                         break;
2553                                 case 0x83: /* any */
2554                                         ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2555                                                         tvb, hdr_start, offset - hdr_start, "*");
2556                                         ok = TRUE;
2557                                         break;
2558                         }
2559                         off++;
2560                 } else {
2561                         get_token_text(str, tvb, off, len, ok);
2562                         if (ok) {
2563                                 ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2564                                                 tvb, hdr_start, offset - hdr_start, str);
2565                                 g_free(str);
2566                         }
2567                         off += len;
2568                 }
2569                 if (ok) {
2570                         /* Remember: offset == val_start + val_len_len + val_len */
2571                         if (off < offset) { /* Add Q-value if available */
2572                                 parameter_tree = proto_item_add_subtree(ti, ett_header);
2573                                 off = parameter_value_q(parameter_tree, ti, tvb, off);
2574                         }
2575                 }
2576         wkh_4_End(hf_hdr_accept_encoding);
2577 }
2578
2579
2580 /*
2581  * Content-disposition-value = Value-length ( Disposition ) *( Parameter )
2582  *      Disposition = Form-data | Attachment | Inline | Token-text
2583  *      Form-data = 0x80
2584  *      Attachment = 0x81
2585  *      Inline = 0x82
2586  * We handle this as:
2587  *      Value-length ( Short-integer | Text-string ) *( Parameter )
2588  */
2589 static guint32
2590 wkh_content_disposition(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2591 {
2592         wkh_0_Declarations;
2593         guint32 len, off;
2594         guint8 peek;
2595         gchar *str;
2596         proto_tree *parameter_tree = NULL;
2597
2598         wkh_1_WellKnownValue;
2599                 /* Invalid */
2600         wkh_2_TextualValue;
2601                 /* Invalid */
2602         wkh_3_ValueWithLength;
2603                 off = val_start + val_len_len;
2604                 peek = tvb_get_guint8(tvb, off);
2605                 if (is_short_integer(peek)) {
2606                         switch (peek) {
2607                                 case 0x80: /* form-data */
2608                                         ti = proto_tree_add_string(tree, hf_hdr_content_disposition,
2609                                                         tvb, hdr_start, offset - hdr_start, "form-data");
2610                                         ok = TRUE;
2611                                         break;
2612                                 case 0x81: /* attachment */
2613                                         ti = proto_tree_add_string(tree, hf_hdr_content_disposition,
2614                                                         tvb, hdr_start, offset - hdr_start, "attachment");
2615                                         ok = TRUE;
2616                                         break;
2617                                 case 0x82: /* inline */
2618                                         ti = proto_tree_add_string(tree, hf_hdr_content_disposition,
2619                                                         tvb, hdr_start, offset - hdr_start, "inline");
2620                                         ok = TRUE;
2621                                         break;
2622                         }
2623                         off++;
2624                 } else {
2625                         get_token_text(str, tvb, off, len, ok);
2626                         if (ok) {
2627                                 ti = proto_tree_add_string(tree, hf_hdr_content_disposition,
2628                                                 tvb, hdr_start, offset - hdr_start, str);
2629                                 g_free(str);
2630                         }
2631                         off += len;
2632                 }
2633                 if ((ok) && (off < offset)) {
2634                         /* Remember: offset == val_start + val_len_len + val_len */
2635                         parameter_tree = proto_item_add_subtree(ti, ett_header);
2636                         while (off < offset) { /* Add parameters if available */
2637                                 off = parameter(parameter_tree, ti, tvb, off, offset - off);
2638                         }
2639                 }
2640         wkh_4_End(hf_hdr_content_disposition);
2641 }
2642
2643
2644 /*
2645  * Common code for headers with only a textual value
2646  * is written in the macro below:
2647  */
2648 #define wkh_text_header(underscored,Text) \
2649 static guint32 \
2650 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2651 { \
2652         wkh_0_Declarations; \
2653         \
2654         wkh_1_WellKnownValue; \
2655                 /* Invalid */ \
2656         wkh_2_TextualValue; \
2657                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2658                                 tvb, hdr_start, offset - hdr_start, val_str); \
2659                 ok = TRUE; \
2660         wkh_3_ValueWithLength; \
2661                 /* Invalid */ \
2662         wkh_4_End(hf_hdr_ ## underscored); \
2663 }
2664
2665 /* Text-only headers: */
2666 wkh_text_header(content_base, "Content-Base")
2667 wkh_text_header(content_location, "Content-Location")
2668 wkh_text_header(etag, "ETag")
2669 wkh_text_header(from, "From")
2670 wkh_text_header(host, "Host")
2671 wkh_text_header(if_match, "If-Match")
2672 wkh_text_header(if_none_match, "If-None-Match")
2673 wkh_text_header(location, "Location")
2674 wkh_text_header(referer, "Referer")
2675 wkh_text_header(server, "Server")
2676 wkh_text_header(user_agent, "User-Agent")
2677 wkh_text_header(upgrade, "Upgrade")
2678 wkh_text_header(via, "Via")
2679 wkh_text_header(content_uri, "Content-Uri")
2680 wkh_text_header(initiator_uri, "Initiator-Uri")
2681 wkh_text_header(profile, "Profile")
2682
2683 /*
2684  * Same for quoted-string value
2685  */
2686 #define wkh_quoted_string_header(underscored,Text) \
2687 static guint32 \
2688 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2689 { \
2690         wkh_0_Declarations; \
2691         gchar *str; \
2692         \
2693         wkh_1_WellKnownValue; \
2694                 /* Invalid */ \
2695         wkh_2_TextualValue; \
2696                 if (is_quoted_string(val_str[0])) { \
2697                         if (is_quoted_string(val_str[val_len-2])) { \
2698                                 /* Trailing quote - issue a warning */ \
2699                                 str = g_strdup_printf("%s" TrailingQuoteWarning, val_str); \
2700                         } else { /* OK (no trailing quote) */ \
2701                                 str = g_strdup_printf("%s\"", val_str); \
2702                         } \
2703                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2704                                         tvb, hdr_start, offset - hdr_start, str); \
2705                         g_free(str); \
2706                 } else { \
2707                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2708                                         tvb, hdr_start, offset - hdr_start, val_str); \
2709                         proto_item_append_text(ti, \
2710                                         " <Warning: should be encoded as a Quoted-string>"); \
2711                 } \
2712                 ok = TRUE; \
2713         wkh_3_ValueWithLength; \
2714                 /* Invalid */ \
2715         wkh_4_End(hf_hdr_ ## underscored); \
2716 }
2717
2718 wkh_quoted_string_header(content_id, "Content-ID")
2719
2720
2721 /*
2722  * Common code for headers with only a textual or a date value
2723  * is written in the macro below:
2724  */
2725 #define wkh_text_or_date_value_header(underscored,Text) \
2726 static guint32 \
2727 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2728 { \
2729         wkh_0_Declarations; \
2730         guint32 val = 0, off = val_start, len; \
2731         nstime_t tv; \
2732         gchar *str; /* may not be freed! */ \
2733         \
2734         wkh_1_WellKnownValue; \
2735                 /* Invalid */ \
2736         wkh_2_TextualValue; \
2737                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2738                                 tvb, hdr_start, offset - hdr_start, val_str); \
2739                 ok = TRUE; \
2740         wkh_3_ValueWithLength; \
2741                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
2742                         get_date_value(val, tvb, off, len, ok); \
2743                         if (ok) { \
2744                                 tv.secs = val; \
2745                                 tv.nsecs = 0; \
2746                                 str = abs_time_to_str(&tv); \
2747                                 g_assert(str); \
2748                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2749                                                 tvb, hdr_start, offset - hdr_start, str); \
2750                                 /* BEHOLD: do NOT try to free str, as this generates a core
2751                                  * dump!  It looks like abs_time_to_str() is buggy or works
2752                                  * with static data. */ \
2753                         } \
2754                 } \
2755         wkh_4_End(hf_hdr_ ## underscored); \
2756 }
2757
2758 /* If-Range */
2759 wkh_text_or_date_value_header(if_range,"If-Range")
2760
2761
2762 /*
2763  * Common code for headers with only a date value
2764  * is written in the macro below:
2765  */
2766 #define wkh_date_value_header(underscored,Text) \
2767 static guint32 \
2768 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2769 { \
2770         wkh_0_Declarations; \
2771         guint32 val = 0, off = val_start, len; \
2772         nstime_t tv; \
2773         gchar *str; /* may not be freed! */ \
2774         \
2775         wkh_1_WellKnownValue; \
2776                 /* Invalid */ \
2777         wkh_2_TextualValue; \
2778                 /* Invalid */ \
2779         wkh_3_ValueWithLength; \
2780                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
2781                         get_date_value(val, tvb, off, len, ok); \
2782                         if (ok) { \
2783                                 tv.secs = val; \
2784                                 tv.nsecs = 0; \
2785                                 str = abs_time_to_str(&tv); \
2786                                 g_assert(str); \
2787                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2788                                                 tvb, hdr_start, offset - hdr_start, str); \
2789                                 /* BEHOLD: do NOT try to free str, as this generates a core
2790                                  * dump!  It looks like abs_time_to_str() is buggy or works
2791                                  * with static data. */ \
2792                         } \
2793                 } \
2794         wkh_4_End(hf_hdr_ ## underscored); \
2795 }
2796
2797 /* Date-value only headers: */
2798 wkh_date_value_header(date, "Date")
2799 wkh_date_value_header(expires, "Expires")
2800 wkh_date_value_header(if_modified_since, "If-Modified-Since")
2801 wkh_date_value_header(if_unmodified_since, "If-Unmodified-Since")
2802 wkh_date_value_header(last_modified, "Last-Modified")
2803
2804
2805 /* Date-value with special interpretation of zero value */
2806 #define wkh_tod_value_header(underscored,Text) \
2807 static guint32 \
2808 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2809 { \
2810         wkh_0_Declarations; \
2811         guint32 val = 0, off = val_start, len; \
2812         nstime_t tv; \
2813         gchar *str; /* may not be freed! */ \
2814         \
2815         wkh_1_WellKnownValue; \
2816                 if (val_id == 0x80) { /* Openwave TOD header uses this format */ \
2817                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2818                                         tvb, hdr_start, offset - hdr_start, \
2819                                         "Requesting Time Of Day"); \
2820                         proto_item_append_text(ti, \
2821                                         " <Warning: should be encoded as long-integer>"); \
2822                         ok = TRUE; \
2823                 } \
2824                 /* It seems VERY unlikely that we'll see date values within the first \
2825                  * 127 seconds of the UNIX 1-1-1970 00:00:00 start of the date clocks \
2826                  * so I assume such a value is a genuine error */ \
2827         wkh_2_TextualValue; \
2828                 /* Invalid */ \
2829         wkh_3_ValueWithLength; \
2830                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
2831                         get_date_value(val, tvb, off, len, ok); \
2832                         if (ok) { \
2833                                 if (val == 0) { \
2834                                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2835                                                         tvb, hdr_start, offset - hdr_start, \
2836                                                         "Requesting Time Of Day"); \
2837                                 } else { \
2838                                         tv.secs = val; \
2839                                         tv.nsecs = 0; \
2840                                         str = abs_time_to_str(&tv); \
2841                                         g_assert(str); \
2842                                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2843                                                         tvb, hdr_start, offset - hdr_start, str); \
2844                                 } \
2845                         } \
2846                 } \
2847         wkh_4_End(hf_hdr_ ## underscored); \
2848 }
2849
2850 wkh_tod_value_header(x_wap_tod, "X-Wap-Tod")
2851
2852
2853 /*
2854  * Age-value: Delta-seconds-value
2855  */
2856 static guint32
2857 wkh_age(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2858 {
2859         wkh_0_Declarations;
2860         guint32 val = 0, off = val_start, len;
2861
2862         wkh_1_WellKnownValue;
2863                 val = val_id & 0x7F;
2864                 val_str = g_strdup_printf("%u second%s", val, PLURALIZE(val));
2865                 ti = proto_tree_add_string(tree, hf_hdr_age,
2866                                 tvb, hdr_start, offset - hdr_start, val_str);
2867                 g_free(val_str); /* proto_XXX creates a copy */
2868                 ok = TRUE;
2869         wkh_2_TextualValue;
2870                 /* Invalid */
2871         wkh_3_ValueWithLength;
2872                 if (val_id <= 4) { /* Length field already parsed by macro! */
2873                         get_long_integer(val, tvb, off, len, ok);
2874                         if (ok) {
2875                                 val_str = g_strdup_printf("%u second%s", val, PLURALIZE(val));
2876                                 ti = proto_tree_add_string(tree, hf_hdr_age,
2877                                                 tvb, hdr_start, offset - hdr_start, val_str);
2878                                 g_free(val_str); /* proto_XXX creates a copy */
2879                         }
2880                 }
2881         wkh_4_End(hf_hdr_age);
2882 }
2883
2884
2885 /*
2886  * Template for Integer lookup or text value headers:
2887  */
2888 #define wkh_integer_lookup_or_text_value(underscored,Text,valueString,valueName) \
2889 static guint32 \
2890 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2891 { \
2892         wkh_0_Declarations; \
2893         guint32 val = 0, off = val_start, len; \
2894         \
2895         wkh_1_WellKnownValue; \
2896                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2897                                 tvb, hdr_start, offset - hdr_start, \
2898                                 val_to_str(val_id & 0x7F, valueString, \
2899                                 "(Unknown " valueName " identifier 0x%X)")); \
2900                 ok = TRUE; \
2901         wkh_2_TextualValue; \
2902                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2903                                 tvb, hdr_start, offset - hdr_start, val_str); \
2904                 ok = TRUE; \
2905         wkh_3_ValueWithLength; \
2906                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
2907                         get_long_integer(val, tvb, off, len, ok); \
2908                         if (ok) { \
2909                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2910                                                 tvb, hdr_start, offset - hdr_start, \
2911                                                 val_to_str(val_id & 0x7F, valueString, \
2912                                                 "(Unknown " valueName " identifier 0x%X)")); \
2913                         } \
2914                 } \
2915         wkh_4_End(hf_hdr_ ## underscored); \
2916 }
2917
2918 /*
2919  * Wap-application-value: Uri-value | Integer-value
2920  */
2921 wkh_integer_lookup_or_text_value(x_wap_application_id, "X-Wap-Application-Id",
2922                 vals_wap_application_ids, "WAP application")
2923 wkh_integer_lookup_or_text_value(accept_application, "Accept-Application",
2924                 vals_wap_application_ids, "WAP application")
2925 wkh_integer_lookup_or_text_value(content_language, "Content-Language",
2926                 vals_languages, "language")
2927 /* NOTE - Although the WSP spec says this is an integer-value, the WSP headers
2928  * are encoded as a 7-bit entity! */
2929 wkh_integer_lookup_or_text_value(trailer, "Trailer",
2930                 vals_field_names, "well-known-header")
2931
2932
2933 /*
2934  * Challenge
2935  */
2936
2937 /*
2938  * Common code for headers with only a challenge value
2939  * is written in the macro below:
2940  */
2941 #define wkh_challenge_value_header(underscored,Text) \
2942 static guint32 \
2943 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, \
2944                 guint32 hdr_start) \
2945 { \
2946         wkh_0_Declarations; \
2947         guint8 peek; \
2948         guint32 off, len; \
2949         proto_tree *subtree; \
2950         gchar *str; \
2951         \
2952         wkh_1_WellKnownValue; \
2953                 /* Invalid */ \
2954         wkh_2_TextualValue; \
2955                 /* Invalid */ \
2956         wkh_3_ValueWithLength; \
2957                 off = val_start + val_len_len; \
2958                 peek = tvb_get_guint8(tvb, off); \
2959                 if (peek == 0x80) { /* Basic */ \
2960                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2961                                         tvb, hdr_start, offset - hdr_start, "basic"); \
2962                         subtree = proto_item_add_subtree(ti, ett_header); \
2963                         proto_tree_add_string(subtree, hf_hdr_ ## underscored ## _scheme, \
2964                                         tvb, off, 1, "basic"); \
2965                         off++; \
2966                         /* Realm: text-string */ \
2967                         get_text_string(str,tvb,off,len,ok); \
2968                         if (ok) { \
2969                                 proto_tree_add_string(subtree, \
2970                                                 hf_hdr_ ## underscored ## _realm, \
2971                                                 tvb, off, len, str); \
2972                                 val_str = g_strdup_printf("; realm=%s", str); \
2973                                 proto_item_append_string(ti, val_str); \
2974                                 g_free(val_str); \
2975                                 g_free(str); \
2976                                 off += len; \
2977                         } \
2978                 } else { /* Authentication-scheme: token-text */ \
2979                         get_token_text(str, tvb, off, len, ok); \
2980                         if (ok) { \
2981                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2982                                                 tvb, hdr_start, off - hdr_start, str); \
2983                                 subtree = proto_item_add_subtree(ti, ett_header); \
2984                                 proto_tree_add_string(subtree, \
2985                                                 hf_hdr_ ## underscored ## _scheme, \
2986                                                 tvb, hdr_start, off - hdr_start, str); \
2987                                 g_free(str); \
2988                                 off += len; \
2989                                 /* Realm: text-string */ \
2990                                 get_text_string(str,tvb,off,len,ok); \
2991                                 if (ok) { \
2992                                         proto_tree_add_string(subtree, \
2993                                                         hf_hdr_ ## underscored ## _realm, \
2994                                                         tvb, off, len, str); \
2995                                         val_str = g_strdup_printf("; realm=%s", str); \
2996                                         proto_item_append_string(ti, val_str); \
2997                                         g_free(val_str); \
2998                                         g_free(str); \
2999                                         off += len; \
3000                                         /* Auth-params: parameter - TODO */ \
3001                                         while (off < offset) /* Parse parameters */ \
3002                                                 off = parameter(subtree, ti, tvb, off, offset - off); \
3003                                 } \
3004                         } \
3005                 } \
3006         wkh_4_End(hf_hdr_ ## underscored); \
3007 }
3008
3009 /* Challenge-value only headers: */
3010 wkh_challenge_value_header(www_authenticate, "WWW-Authenticate")
3011 wkh_challenge_value_header(proxy_authenticate, "Proxy-Authenticate")
3012
3013
3014 /*
3015  * Credentials
3016  */
3017
3018 /*
3019  * Common code for headers with only a credentials value
3020  * is written in the macro below:
3021  */
3022 #define wkh_credentials_value_header(underscored,Text) \
3023 static guint32 \
3024 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, \
3025                 guint32 hdr_start) \
3026 { \
3027         wkh_0_Declarations; \
3028         guint8 peek; \
3029         guint32 off, len; \
3030         proto_tree *subtree; \
3031         gchar *str; \
3032         \
3033         wkh_1_WellKnownValue; \
3034                 /* Invalid */ \
3035         wkh_2_TextualValue; \
3036                 /* Invalid */ \
3037         wkh_3_ValueWithLength; \
3038                 off = val_start + val_len_len; \
3039                 peek = tvb_get_guint8(tvb, off); \
3040                 if (peek == 0x80) { /* Basic */ \
3041                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3042                                         tvb, hdr_start, offset - hdr_start, "basic"); \
3043                         subtree = proto_item_add_subtree(ti, ett_header); \
3044                         proto_tree_add_string(subtree, hf_hdr_ ## underscored ## _scheme, \
3045                                         tvb, off, 1, "basic"); \
3046                         off++; \
3047                         /* User-id: text-string */ \
3048                         get_text_string(str,tvb,off,len,ok); \
3049                         if (ok) { \
3050                                 proto_tree_add_string(subtree, \
3051                                                 hf_hdr_ ## underscored ## _user_id, \
3052                                                 tvb, off, len, str); \
3053                                 val_str = g_strdup_printf("; user-id=%s", str); \
3054                                 proto_item_append_string(ti, val_str); \
3055                                 g_free(val_str); \
3056                                 g_free(str); \
3057                                 off += len; \
3058                                 /* Password: text-string */ \
3059                                 get_text_string(str,tvb,off,len,ok); \
3060                                 if (ok) { \
3061                                         proto_tree_add_string(subtree, \
3062                                                         hf_hdr_ ## underscored ## _password, \
3063                                                         tvb, off, len, str); \
3064                                         val_str = g_strdup_printf("; password=%s", str); \
3065                                         proto_item_append_string(ti, val_str); \
3066                                         g_free(val_str); \
3067                                         g_free(str); \
3068                                         off += len; \
3069                                 } \
3070                         } \
3071                 } else { /* Authentication-scheme: token-text */ \
3072                         get_token_text(str, tvb, off, len, ok); \
3073                         if (ok) { \
3074                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3075                                                 tvb, hdr_start, off - hdr_start, str); \
3076                                 subtree = proto_item_add_subtree(ti, ett_header); \
3077                                 proto_tree_add_string(subtree, \
3078                                                 hf_hdr_ ## underscored ## _scheme, \
3079                                                 tvb, hdr_start, off - hdr_start, str); \
3080                                 g_free(str); \
3081                                 off += len; \
3082                                 /* Auth-params: parameter - TODO */ \
3083                                 while (off < offset) /* Parse parameters */ \
3084                                         off = parameter(subtree, ti, tvb, off, offset - off); \
3085                         } \
3086                 } \
3087         wkh_4_End(hf_hdr_ ## underscored); \
3088 }
3089
3090 /* Credentials-value only headers: */
3091 wkh_credentials_value_header(authorization, "Authorization")
3092 wkh_credentials_value_header(proxy_authorization, "Proxy-Authorization")
3093
3094
3095 /*
3096  * Content-md5-value = 16*16 OCTET
3097  */
3098 static guint32
3099 wkh_content_md5 (proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3100 {
3101         wkh_0_Declarations;
3102         guint32 off;
3103
3104         wkh_1_WellKnownValue;
3105                 /* Invalid */
3106         wkh_2_TextualValue;
3107                 /* Invalid */
3108         wkh_3_ValueWithLength;
3109                 off = val_start + val_len_len;
3110                 if (val_len == 16) {
3111                         val_str = g_strdup_printf(
3112                                         "%02x%02x%02x%02x%02x%02x%02x%02x"
3113                                         "%02x%02x%02x%02x%02x%02x%02x%02x",
3114                                         tvb_get_guint8(tvb, off),
3115                                         tvb_get_guint8(tvb, off + 1),
3116                                         tvb_get_guint8(tvb, off + 2),
3117                                         tvb_get_guint8(tvb, off + 3),
3118                                         tvb_get_guint8(tvb, off + 4),
3119                                         tvb_get_guint8(tvb, off + 5),
3120                                         tvb_get_guint8(tvb, off + 6),
3121                                         tvb_get_guint8(tvb, off + 7),
3122                                         tvb_get_guint8(tvb, off + 8),
3123                                         tvb_get_guint8(tvb, off + 9),
3124                                         tvb_get_guint8(tvb, off + 10),
3125                                         tvb_get_guint8(tvb, off + 11),
3126                                         tvb_get_guint8(tvb, off + 12),
3127                                         tvb_get_guint8(tvb, off + 13),
3128                                         tvb_get_guint8(tvb, off + 14),
3129                                         tvb_get_guint8(tvb, off + 15)
3130                         );
3131                         ti = proto_tree_add_string(tree, hf_hdr_content_md5,
3132                                         tvb, hdr_start, offset - hdr_start, val_str);
3133                         g_free(val_str);
3134                         ok = TRUE;
3135                 }
3136         wkh_4_End(hf_hdr_content_md5);
3137 }
3138
3139
3140 /*
3141  * Pragma-value = 0x80 | Length Parameter
3142  */
3143 static guint32
3144 wkh_pragma(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3145 {
3146         wkh_0_Declarations;
3147         guint32 off;
3148
3149         wkh_1_WellKnownValue;
3150                 if (val_id == 0x80) {
3151                         ti = proto_tree_add_string(tree, hf_hdr_pragma,
3152                                         tvb, hdr_start, offset - hdr_start, "no-cache");
3153                         ok = TRUE;
3154                 }
3155         wkh_2_TextualValue;
3156                 /* Invalid */
3157         wkh_3_ValueWithLength;
3158                 off = val_start + val_len_len;
3159                 ti = proto_tree_add_string(tree, hf_hdr_pragma,
3160                                 tvb, hdr_start, off - hdr_start, "");
3161                 /* NULL subtree for parameter() results in no subtree
3162                  * TODO - provide a single parameter dissector that appends data
3163                  * to the header field data. */
3164                 off = parameter(NULL, ti, tvb, off, offset - off);
3165                 ok = TRUE;
3166         wkh_4_End(hf_hdr_pragma);
3167 }
3168
3169
3170 /*
3171  * Integer-value
3172  */
3173 #define wkh_integer_value_header(underscored,Text) \
3174 static guint32 \
3175 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
3176 { \
3177         wkh_0_Declarations; \
3178         guint32 val = 0, off = val_start, len; \
3179         gchar *str; /* may not be freed! */ \
3180         \
3181         wkh_1_WellKnownValue; \
3182                 str = g_strdup_printf("%u", val_id & 0x7F); \
3183                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3184                                 tvb, hdr_start, offset - hdr_start, str); \
3185                 g_free(str); \
3186                 ok = TRUE; \
3187         wkh_2_TextualValue; \
3188                 /* Invalid */ \
3189         wkh_3_ValueWithLength; \
3190                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
3191                         get_long_integer(val, tvb, off, len, ok); \
3192                         if (ok) { \
3193                                 str = g_strdup_printf("%u", val); \
3194                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3195                                                 tvb, hdr_start, offset - hdr_start, str); \
3196                                 g_free(str); \
3197                         } \
3198                 } \
3199         wkh_4_End(hf_hdr_ ## underscored); \
3200 }
3201
3202 wkh_integer_value_header(content_length, "Content-Length")
3203 wkh_integer_value_header(max_forwards, "Max-Forwards")
3204
3205
3206 #define wkh_integer_lookup_value_header(underscored,Text,valueString,valueName) \
3207 static guint32 \
3208 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
3209 { \
3210         wkh_0_Declarations; \
3211         guint32 val = 0, off = val_start, len; \
3212         \
3213         wkh_1_WellKnownValue; \
3214                 val_str = match_strval(val_id & 0x7F, valueString); \
3215                 if (val_str) { \
3216                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3217                                 tvb, hdr_start, offset - hdr_start, val_str); \
3218                         ok = TRUE; \
3219                 } else { \
3220                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3221                                 tvb, hdr_start, offset - hdr_start, \
3222                                 "<Unknown " valueName ">"); \
3223                 } \
3224         wkh_2_TextualValue; \
3225                 /* Invalid */ \
3226         wkh_3_ValueWithLength; \
3227                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
3228                         get_long_integer(val, tvb, off, len, ok); \
3229                         if (ok) { \
3230                                 val_str = match_strval(val_id & 0x7F, valueString); \
3231                                 if (val_str) { \
3232                                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3233                                                 tvb, hdr_start, offset - hdr_start, val_str); \
3234                                         ok = TRUE; \
3235                                 } else { \
3236                                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3237                                                 tvb, hdr_start, offset - hdr_start, \
3238                                                 "<Unknown " valueName ">"); \
3239                                 } \
3240                         } \
3241                 } \
3242         wkh_4_End(hf_hdr_ ## underscored); \
3243 }
3244
3245 wkh_integer_lookup_value_header(bearer_indication, "Bearer-Indication",
3246                 vals_bearer_types, "bearer type")
3247
3248
3249 /*
3250  * Cache-control-value
3251  */
3252 static guint32
3253 wkh_cache_control(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3254 {
3255         wkh_0_Declarations;
3256         guint32 off, len, val = 0;
3257         guint8 peek, cache_control_directive;
3258         gchar *str;
3259
3260         wkh_1_WellKnownValue;
3261                 val = val_id & 0x7F;
3262                 val_str = match_strval(val, vals_cache_control);
3263                 if (val_str) {
3264                         ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3265                                         tvb, hdr_start, offset - hdr_start, val_str);
3266                         ok = TRUE;
3267                 }
3268         wkh_2_TextualValue;
3269                 ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3270                                 tvb, hdr_start, offset - hdr_start, val_str);
3271                 ok = TRUE;
3272         wkh_3_ValueWithLength;
3273                 /* General form:
3274                  *        ( no-cache | private ) 1*( Field-name )
3275                  *      | ( max-age | max-stale | min-fresh | s-maxage) Delta-seconds-value
3276                  *      | Token-text ( Integer-value | Text-value )
3277                  * Where:
3278                  *      Field-name = Short-integer | Token-text
3279                  */
3280                 off = val_start + val_len_len;
3281                 cache_control_directive = tvb_get_guint8(tvb, off++);
3282                 if (cache_control_directive & 0x80) { /* Well known cache directive */
3283                         switch (cache_control_directive & 0x7F) {
3284                                 case CACHE_CONTROL_NO_CACHE:
3285                                 case CACHE_CONTROL_PRIVATE:
3286                                         ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3287                                                         tvb, hdr_start, offset - hdr_start,
3288                                                         val_to_str (cache_control_directive & 0x7F, vals_cache_control,
3289                                                                 "<Unknown cache control directive 0x%02X>"));
3290                                         /* TODO: split multiple entries */
3291                                         while (ok && (off < offset)) { /* 1*( Field-name ) */
3292                                                 ok = TRUE;
3293                                                 peek = tvb_get_guint8(tvb, off);
3294                                                 if (peek & 0x80) { /* Well-known-field-name */
3295                                                         proto_item_append_string(ti,
3296                                                                         val_to_str (peek, vals_field_names,
3297                                                                                 "<Unknown WSP header field 0x%02X>"));
3298                                                         off++;
3299                                                 } else { /* Token-text */
3300                                                         get_token_text(val_str, tvb, off, len, ok);
3301                                                         if (ok) {
3302                                                                 proto_item_append_string(ti, val_str);
3303                                                                 g_free(val_str);
3304                                                                 off += len;
3305                                                         }
3306                                                 }
3307                                         }
3308                                         break;
3309
3310                                 case CACHE_CONTROL_MAX_AGE:
3311                                 case CACHE_CONTROL_MAX_STALE:
3312                                 case CACHE_CONTROL_MIN_FRESH:
3313                                 case CACHE_CONTROL_S_MAXAGE:
3314                                         ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3315                                                         tvb, hdr_start, offset - hdr_start,
3316                                                         val_to_str (cache_control_directive & 0x7F, vals_cache_control,
3317                                                                 "<Unknown cache control directive 0x%02X>"));
3318                                         get_delta_seconds_value(val, tvb, off, len, ok);
3319                                         if (ok) {
3320                                                 val_str = g_strdup_printf("=%u second%s",
3321                                                                 val, PLURALIZE(val));
3322                                                 proto_item_append_string(ti, val_str);
3323                                                 g_free(val_str); /* proto_XXX creates a copy */
3324                                         }
3325                                         break;
3326
3327                                 default:
3328                                         /* ok = FALSE */
3329                                         break;
3330                         }
3331                 } else if (is_token_text(cache_control_directive)) {
3332                         get_token_text(val_str, tvb, off, len, ok);
3333                         if (ok) {
3334                                 ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3335                                                 tvb, hdr_start, offset - hdr_start, val_str);
3336                                 g_free(val_str);
3337                                 get_integer_value(val, tvb, off, len, ok);
3338                                 if (ok) { /* Integer-value */
3339                                         val_str = g_strdup_printf("=%u", val);
3340                                         proto_item_append_string(ti, val_str);
3341                                         g_free(val_str); /* proto_XXX creates a copy */
3342                                 } else { /* Text-value */
3343                                         get_text_string(val_str, tvb, off, len, ok);
3344                                         if (ok) {
3345                                                 if (is_quoted_string(val_str[0])) {
3346                                                         if (is_quoted_string(val_str[len-2])) {
3347                                                                 /* Trailing quote - issue a warning */
3348                                                                 str = g_strdup_printf("%s" TrailingQuoteWarning,
3349                                                                                 val_str);
3350                                                         } else { /* OK (no trailing quote) */
3351                                                                 str = g_strdup_printf("%s\"", val_str);
3352                                                         }
3353                                                         proto_item_append_string(ti, str);
3354                                                         g_free(str);
3355                                                 } else { /* Token-text | 0x00 */
3356                                                         /* TODO - check that we have Token-text or 0x00 */
3357                                                         proto_item_append_string(ti, val_str);
3358                                                 }
3359                                                 g_free(val_str);
3360                                         }
3361                                 }
3362                         }
3363                 }
3364         wkh_4_End(hf_hdr_cache_control);
3365 }
3366
3367
3368 /*
3369  * Warning-value =
3370  *        Short-integer
3371  *      | ( Value-length Short-integer Text-string Text-string )
3372  */
3373 static guint32
3374 wkh_warning(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3375 {
3376         wkh_0_Declarations;
3377         guint32 off, len, val;
3378         guint8 warn_code;
3379         gchar *str;
3380         proto_tree *subtree;
3381
3382         /* TODO - subtree with values */
3383
3384         wkh_1_WellKnownValue;
3385                 val = val_id & 0x7F;
3386                 val_str = match_strval(val, vals_wsp_warning_code);
3387                 if (val_str) {
3388                         ti = proto_tree_add_string(tree, hf_hdr_warning,
3389                                         tvb, hdr_start, offset - hdr_start, val_str);
3390                         subtree = proto_item_add_subtree(ti, ett_header);
3391                         proto_tree_add_uint(subtree, hf_hdr_warning_code,
3392                                         tvb, val_start, 1, val);
3393                         ok = TRUE;
3394                 }
3395         wkh_2_TextualValue;
3396                 /* Invalid */
3397         wkh_3_ValueWithLength;
3398                 /* TODO - subtree with individual values */
3399                 off = val_start + val_len_len;
3400                 warn_code = tvb_get_guint8(tvb, off);
3401                 if (warn_code & 0x80) { /* Well known warn code */
3402                         val = warn_code & 0x7f;
3403                         val_str = match_strval(val, vals_wsp_warning_code_short);
3404                         if (val_str) { /* OK */
3405                                 str = g_strdup_printf("code=%s", val_str);
3406                                 ti = proto_tree_add_string(tree, hf_hdr_warning,
3407                                                 tvb, hdr_start, offset - hdr_start, str);
3408                                 g_free(str);
3409                                 subtree = proto_item_add_subtree(ti, ett_header);
3410                                 proto_tree_add_uint(subtree, hf_hdr_warning_code,
3411                                                 tvb, off, 1, val);
3412                                 off++; /* Now skip to the warn-agent subfield */
3413                                 get_text_string(str, tvb, off, len, ok);
3414                                 if (ok) { /* Valid warn-agent string */
3415                                         proto_tree_add_string(subtree, hf_hdr_warning_agent,
3416                                                         tvb, off, len, str);
3417                                         val_str = g_strdup_printf("; agent=%s", str);
3418                                         proto_item_append_string(ti, val_str);
3419                                         g_free(val_str); /* proto_XXX creates a copy */
3420                                         g_free(str);
3421                                         off += len;
3422                                         get_text_string(str, tvb, off, len, ok);
3423                                         if (ok) { /* Valid warn-text string */
3424                                                 proto_tree_add_string(subtree,
3425                                                                 hf_hdr_warning_text,
3426                                                                 tvb, off, len, str);
3427                                                 val_str = g_strdup_printf("; text=%s", str);
3428                                                 proto_item_append_string(ti, val_str);
3429                                                 g_free(val_str); /* proto_XXX creates a copy */
3430                                                 g_free(str);
3431                                                 off += len;
3432                                         }
3433                                 }
3434                         }
3435                 }
3436         wkh_4_End(hf_hdr_warning);
3437 }
3438
3439
3440 /*
3441  * Profile-warning-value =
3442  *        Short-integer
3443  *      | ( Value-length Short-integer Text-string *( Date-value ) )
3444  */
3445 static guint32
3446 wkh_profile_warning(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3447 {
3448         wkh_0_Declarations;
3449         guint32 off, len, val = 0;
3450         nstime_t tv;
3451         guint8 warn_code;
3452         gchar *str;
3453
3454         wkh_1_WellKnownValue;
3455                 val = val_id & 0x7F;
3456                 val_str = match_strval(val, vals_wsp_profile_warning_code);
3457                 if (val_str) {
3458                         ti = proto_tree_add_string(tree, hf_hdr_profile_warning,
3459                                         tvb, hdr_start, offset - hdr_start, val_str);
3460                         ok = TRUE;
3461                 }
3462         wkh_2_TextualValue;
3463                 /* Invalid */
3464         wkh_3_ValueWithLength;
3465                 off = val_start + val_len_len;
3466                 warn_code = tvb_get_guint8(tvb, off++);
3467                 if (warn_code & 0x80) { /* Well known warn code */
3468                         val_str = match_strval(val, vals_wsp_profile_warning_code);
3469                         if (val_str) { /* OK */
3470                                 ti = proto_tree_add_string(tree, hf_hdr_profile_warning,
3471                                                 tvb, hdr_start, offset - hdr_start, val_str);
3472                                 get_uri_value(str, tvb, off, len, ok);
3473                                 if (ok) { /* Valid warn-target string */
3474                                         off += len;
3475                                         str = g_strdup_printf("; target=%s", val_str);
3476                                         proto_item_append_string(ti, str);
3477                                         g_free(str); /* proto_XXX creates a copy */
3478                                         /* Add zero or more dates */
3479                                         while (ok && (off < offset)) {
3480                                                 get_date_value(val, tvb, off, len, ok);
3481                                                 if (ok) { /* Valid warn-text string */
3482                                                         off += len;
3483                                                         tv.secs = val;
3484                                                         tv.nsecs = 0;
3485                                                         val_str = abs_time_to_str(&tv);
3486                                                         g_assert(val_str);
3487                                                         str = g_strdup_printf("; date=%s", val_str);
3488                                                         proto_item_append_string(ti, str);
3489                                                         g_free(str); /* proto_XXX creates a copy */
3490                                                         /* BEHOLD: do NOT try to free val_str, as this
3491                                                          * generates a core dump!
3492                                                          * It looks like abs_time_to_str() is
3493                                                          * buggy or works with static data. */
3494                                                 }
3495                                         }
3496                                 }
3497                         }
3498                 }
3499         wkh_4_End(hf_hdr_profile_warning);
3500 }
3501
3502
3503 /* Encoding-version-value =
3504  *        Short-integer
3505  *      | Text-string
3506  *      | Length Short-integer [ Short-integer | text-string ]
3507  */
3508 static guint32 wkh_encoding_version (proto_tree *tree, tvbuff_t *tvb,
3509                 guint32 hdr_start)
3510 {
3511         wkh_0_Declarations;
3512         guint32 off, val, len;
3513         guint8 *str;
3514
3515         wkh_1_WellKnownValue;
3516                 val = val_id & 0x7F;
3517                 val_str = g_strdup_printf("%u.%u", val >> 4, val & 0x0F);
3518                 proto_tree_add_string(tree, hf_hdr_encoding_version,
3519                                 tvb, hdr_start, offset - hdr_start, val_str);
3520                 g_free(val_str);
3521                 ok = TRUE;
3522         wkh_2_TextualValue;
3523                 proto_tree_add_string(tree, hf_hdr_encoding_version,
3524                                 tvb, hdr_start, offset - hdr_start, val_str);
3525                 ok = TRUE;
3526         wkh_3_ValueWithLength;
3527                 off = val_start + val_len_len;
3528                 val = tvb_get_guint8(tvb, off);
3529                 if (val & 0x80) { /* Header Code Page */
3530                         val_str = g_strdup_printf("code-page=%u", val & 0x7F);
3531                         ti = proto_tree_add_string(tree, hf_hdr_encoding_version,
3532                                         tvb, hdr_start, offset - hdr_start, val_str);
3533                         g_free(val_str);
3534                         off++;
3535                         ok = TRUE;
3536                         if (off < offset) { /* Extra version-value */
3537                                 get_version_value(val,val_str,tvb,off,len,ok);
3538                                 if (ok) { /* Always creates a string if OK */
3539                                         str = g_strdup_printf(": %s", val_str);
3540                                         proto_item_append_string(ti, str);
3541                                         g_free(str);
3542                                         g_free(val_str);
3543                                 }
3544                         }
3545                 }
3546
3547         wkh_4_End(hf_hdr_encoding_version);
3548 }
3549
3550
3551 /* Content-range-value =
3552  *        Length Uintvar-integer ( 0x80 | Uintvar-integer )
3553  */
3554 static guint32
3555 wkh_content_range(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3556 {
3557         wkh_0_Declarations;
3558         guint32 off, val, len;
3559         proto_tree *subtree = NULL;
3560
3561         wkh_1_WellKnownValue;
3562                 /* Invalid */
3563         wkh_2_TextualValue;
3564                 /* Invalid */
3565         wkh_3_ValueWithLength;
3566                 off = val_start + val_len_len;
3567                 get_uintvar_integer (val, tvb, off, len, ok); /* Uintvar start */
3568                 if (ok) {
3569                         val_str = g_strdup_printf("first-byte-pos=%u", val);
3570                         ti = proto_tree_add_string(tree, hf_hdr_content_range,
3571                                         tvb, hdr_start, offset - hdr_start, val_str);
3572                         subtree = proto_item_add_subtree(ti, ett_header);
3573                         proto_tree_add_uint(subtree, hf_hdr_content_range_first_byte_pos,
3574                                         tvb, off, len, val);
3575                         g_free(val_str);
3576                         off += len;
3577                         /* Now check next value */
3578                         val = tvb_get_guint8(tvb, off);
3579                         if (val == 0x80) { /* Unknown length */
3580                                 proto_item_append_string(ti, "; entity-length=unknown");
3581                         } else { /* Uintvar entity length */
3582                                 get_uintvar_integer (val, tvb, off, len, ok);
3583                                 if (ok) {
3584                                         val_str = g_strdup_printf("; entity-length=%u", val);
3585                                         proto_item_append_string(ti, val_str);
3586                                         proto_tree_add_uint(subtree,
3587                                                         hf_hdr_content_range_entity_length,
3588                                                         tvb, off, len, val);
3589                                         g_free(val_str);
3590                                 }
3591                         }
3592                 }
3593
3594         wkh_4_End(hf_hdr_content_range);
3595 }
3596
3597
3598 /* Range-value =
3599  *      Length
3600  *              0x80 Uintvar-integer [ Uintvar-integer ]
3601  *        | 0x81 Uintvar-integer
3602  */
3603 static guint32
3604 wkh_range(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3605 {
3606         wkh_0_Declarations;
3607         guint32 off, val, len;
3608         proto_tree *subtree = NULL;
3609
3610         wkh_1_WellKnownValue;
3611                 /* Invalid */
3612         wkh_2_TextualValue;
3613                 /* Invalid */
3614         wkh_3_ValueWithLength;
3615                 off = val_start + val_len_len;
3616                 val = tvb_get_guint8(tvb, off);
3617                 if (val == 0x80) { /* Byte-range */
3618                         ti = proto_tree_add_string(tree, hf_hdr_range,
3619                                         tvb, hdr_start, offset - hdr_start, "byte-range");
3620                         subtree = proto_item_add_subtree(ti, ett_header);
3621                         /* Get the First-byte-pos (Uintvar-integer) */
3622                         get_uintvar_integer (val, tvb, off, len, ok);
3623                         if (ok) {
3624                                 val_str = g_strdup_printf("; first-byte-pos=%u", val);
3625                                 proto_item_append_string(ti, val_str);
3626                                 proto_tree_add_uint(subtree, hf_hdr_range_first_byte_pos,
3627                                                 tvb, off, len, val);
3628                                 g_free(val_str);
3629                                 off += len;
3630                                 /* Get the optional Last-byte-pos (Uintvar-integer) */
3631                                 if (off < offset) {
3632                                         get_uintvar_integer (val, tvb, off, len, ok);
3633                                         if (ok) {
3634                                                 val_str = g_strdup_printf("; last-byte-pos=%u", val);
3635                                                 proto_item_append_string(ti, val_str);
3636                                                 proto_tree_add_uint(subtree,
3637                                                                 hf_hdr_range_last_byte_pos,
3638                                                                 tvb, off, len, val);
3639                                                 g_free(val_str);
3640                                         }
3641                                 }
3642                         }
3643                 } else if (val == 0x81) { /* Suffix-byte-range */
3644                         ti = proto_tree_add_string(tree, hf_hdr_range,
3645                                         tvb, hdr_start, offset - hdr_start, "suffix-byte-range");
3646                         subtree = proto_item_add_subtree(ti, ett_header);
3647                         /* Get the Suffix-length (Uintvar-integer) */
3648                         get_uintvar_integer (val, tvb, off, len, ok);
3649                         if (ok) {
3650                                 val_str = g_strdup_printf("; suffix-length=%u", val);
3651                                 proto_item_append_string(ti, val_str);
3652                                 proto_tree_add_uint(subtree, hf_hdr_range_suffix_length,
3653                                                 tvb, off, len, val);
3654                                 g_free(val_str);
3655                         }
3656                 }
3657
3658         wkh_4_End(hf_hdr_range);
3659 }
3660
3661
3662 /* TE-value =
3663  *        0x81
3664  *      | Value-length (0x82--0x86 | Token-text) [ Q-token Q-value ]
3665  */
3666 static guint32 wkh_te (proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3667 {
3668         wkh_0_Declarations;
3669         guint32 off, val, len;
3670
3671         wkh_1_WellKnownValue;
3672                 if (val_id == 0x81) {
3673                         proto_tree_add_string(tree, hf_hdr_encoding_version,
3674                                         tvb, hdr_start, offset - hdr_start, "trailers");
3675                         ok = TRUE;
3676                 }
3677         wkh_2_TextualValue;
3678                 /* Invalid */
3679         wkh_3_ValueWithLength;
3680                 off = val_start + val_len_len;
3681                 val = tvb_get_guint8(tvb, off);
3682                 if (val & 0x80) { /* Well-known-TE */
3683                         val_str = match_strval((val & 0x7F), vals_well_known_te);
3684                         if (val_str) {
3685                                 ti = proto_tree_add_string(tree, hf_hdr_te,
3686                                                 tvb, hdr_start, off - hdr_start, val_str);
3687                                 off++;
3688                                 ok = TRUE;
3689                         }
3690                 } else { /* TE in Token-text format */
3691                         get_token_text(val_str, tvb, off, len, ok);
3692                         ti = proto_tree_add_string(tree, hf_hdr_te,
3693                                         tvb, hdr_start, off - hdr_start, val_str);
3694                         g_free(val_str);
3695                         off += len;
3696                         ok = TRUE;
3697                 }
3698                 if ((ok) && (off < offset)) { /* Q-token Q-value */
3699                         /* TODO */
3700                 }
3701
3702         wkh_4_End(hf_hdr_te);
3703 }
3704
3705
3706 /****************************************************************************
3707  *                     O p e n w a v e   h e a d e r s
3708  ****************************************************************************/
3709
3710
3711
3712
3713 /*
3714  * Redefine the WellKnownValue parsing so Openwave header field names are used
3715  * are used instead of the default WSP header field names
3716  */
3717 #undef wkh_1_WellKnownValue
3718 #define wkh_1_WellKnownValue                    /* Parse Well Known Value */ \
3719         proto_tree_add_string_hidden(tree, hf_hdr_name, \
3720                         tvb, hdr_start, offset - hdr_start, \
3721                         val_to_str (hdr_id, vals_openwave_field_names, \
3722                                         "<Unknown WSP header field 0x%02X>")); \
3723         if (val_id & 0x80) { /* Well-known value */ \
3724                 offset++; \
3725                 /* Well-known value processing starts HERE \
3726                  * \
3727                  * BEGIN */
3728
3729 /*
3730  * Redefine the End parsing so Openwave header field names are used
3731  * instead of the default WSP field names
3732  */
3733 #undef wkh_4_End
3734 #define wkh_4_End(hf)                                           /* End of value parsing */ \
3735                 /* END */ \
3736         } \
3737         /* Check for errors */ \
3738         if (! ok) { \
3739                 if (ti) { /* Append to protocol tree item label */ \
3740                         proto_item_append_text(ti, \
3741                                         "<Error: Invalid header value>"); \
3742                 } else if (hf > 0) { /* Create protocol tree item */ \
3743                         proto_tree_add_string(tree, hf, \
3744                                         tvb, hdr_start, offset - hdr_start, \
3745                                         " <Error: Invalid header value>"); \
3746                 } else { /* Create anonymous header field entry */ \
3747                         proto_tree_add_text(tree, tvb, hdr_start, offset - hdr_start, \
3748                                         "%s: <Error: Invalid header value>", \
3749                                         val_to_str (hdr_id, vals_openwave_field_names, \
3750                                                 "<Unknown WSP header field 0x%02X>")); \
3751                 } \
3752         } \
3753         return offset;
3754
3755
3756 /* Dissect the Openwave header value (generic) */
3757 static guint32
3758 wkh_openwave_default(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3759 {
3760         wkh_0_Declarations;
3761
3762         ok = TRUE; /* Bypass error checking as we don't parse the values! */
3763
3764         wkh_1_WellKnownValue;
3765                 ti = proto_tree_add_text(tree, tvb, hdr_start, offset - hdr_start,
3766                                 "%s: (Undecoded well-known value 0x%02x)",
3767                                 val_to_str (hdr_id, vals_openwave_field_names,
3768                                         "<Unknown WSP header field 0x%02X>"), val_id & 0x7F);
3769         wkh_2_TextualValue;
3770                 ti = proto_tree_add_text(tree,tvb,hdr_start, offset - hdr_start,
3771                                 "%s: %s",
3772                                 val_to_str (hdr_id, vals_openwave_field_names,
3773                                         "<Unknown WSP header field 0x%02X>"), val_str);
3774         wkh_3_ValueWithLength;
3775                 ti = proto_tree_add_text(tree, tvb, hdr_start, offset - hdr_start,
3776                                 "%s: (Undecoded value in general form with length indicator)",
3777                                 val_to_str (hdr_id, vals_openwave_field_names,
3778                                         "<Unknown WSP header field 0x%02X>"));
3779
3780         wkh_4_End(HF_EMPTY); /* See wkh_default for explanation */
3781 }
3782
3783
3784 /* Textual Openwave headers */
3785 wkh_text_header(openwave_x_up_proxy_operator_domain,
3786                 "x-up-proxy-operator-domain")
3787 wkh_text_header(openwave_x_up_proxy_home_page,
3788                 "x-up-proxy-home-page")
3789 wkh_text_header(openwave_x_up_proxy_uplink_version,
3790                 "x-up-proxy-uplink-version")
3791 wkh_text_header(openwave_x_up_proxy_ba_realm,
3792                 "x-up-proxy-ba-realm")
3793 wkh_text_header(openwave_x_up_proxy_request_uri,
3794                 "x-up-proxy-request-uri")
3795 wkh_text_header(openwave_x_up_proxy_bookmark,
3796                 "x-up-proxy-bookmark")
3797
3798 /* Integer Openwave headers */
3799 wkh_integer_value_header(openwave_x_up_proxy_push_seq,
3800                 "x-up-proxy-push-seq")
3801 wkh_integer_value_header(openwave_x_up_proxy_notify,
3802                 "x-up-proxy-notify")
3803 wkh_integer_value_header(openwave_x_up_proxy_net_ask,
3804                 "x-up-proxy-net-ask")
3805 wkh_integer_value_header(openwave_x_up_proxy_ba_enable,
3806                 "x-up-proxy-ba-enable")
3807 wkh_integer_value_header(openwave_x_up_proxy_redirect_enable,
3808                 "x-up-proxy-redirect-enable")
3809 wkh_integer_value_header(openwave_x_up_proxy_redirect_status,
3810                 "x-up-proxy-redirect-status")
3811 wkh_integer_value_header(openwave_x_up_proxy_linger,
3812                 "x-up-proxy-linger")
3813 wkh_integer_value_header(openwave_x_up_proxy_enable_trust,
3814                 "x-up-proxy-enable-trust")
3815 wkh_integer_value_header(openwave_x_up_proxy_trust,
3816                 "x-up-proxy-trust")
3817
3818 wkh_integer_value_header(openwave_x_up_devcap_has_color,
3819                 "x-up-devcap-has-color")
3820 wkh_integer_value_header(openwave_x_up_devcap_num_softkeys,
3821                 "x-up-devcap-num-softkeys")
3822 wkh_integer_value_header(openwave_x_up_devcap_softkey_size,
3823                 "x-up-devcap-softkey-size")
3824 wkh_integer_value_header(openwave_x_up_devcap_screen_chars,
3825                 "x-up-devcap-screen-chars")
3826 wkh_integer_value_header(openwave_x_up_devcap_screen_pixels,
3827                 "x-up-devcap-screen-pixels")
3828 wkh_integer_value_header(openwave_x_up_devcap_em_size,
3829                 "x-up-devcap-em-size")
3830 wkh_integer_value_header(openwave_x_up_devcap_screen_depth,
3831                 "x-up-devcap-screen-depth")
3832 wkh_integer_value_header(openwave_x_up_devcap_immed_alert,
3833                 "x-up-devcap-immed_alert")
3834 wkh_integer_value_header(openwave_x_up_devcap_gui,
3835                 "x-up-devcap-gui")
3836
3837 /* Openwave Time-Of-Day value header */
3838 wkh_tod_value_header(openwave_x_up_proxy_tod,
3839                 "x-up-proxy-tod")
3840
3841 /* Openwave accept_x_q header */
3842 wkh_accept_x_q_header(openwave_x_up_proxy_trans_charset,
3843                 "x-up-proxy-trans-charset",
3844                 vals_character_sets, "character set")
3845
3846 /* Openwave content type header */
3847 wkh_content_type_header(openwave_x_up_proxy_push_accept,
3848                 "x-up-proxy-push-accept")
3849
3850 /*
3851  * Header value parameter parsing
3852  */
3853 #define InvalidParameterValue(parameter,value) \
3854         "<Error: Invalid " parameter " parameter value: invalid " value ">"
3855
3856
3857
3858
3859
3860 #define parameter_text(hf,lowercase,Uppercase,value) \
3861         DebugLog(("parameter with text_string value: " Uppercase "\n")); \
3862         get_text_string(val_str, tvb, offset, val_len, ok); \
3863         if (ok) { \
3864                 DebugLog(("OK, valid text_string value found!\n")); \
3865                 DebugLog(("Adding val_str to the header field in proto tree\n")); \
3866                 proto_tree_add_string(tree, hf, \
3867                                 tvb, start, type_len + val_len, val_str); \
3868                 DebugLog(("Creating str to append to ti\n")); \
3869                 str = g_strdup_printf("; " lowercase "=%s", val_str); \
3870                 DebugLog(("Appending str to ti\n")); \
3871                 proto_item_append_string(ti, str); \
3872                 DebugLog(("\tFreeing str [%s]\n", str)); \
3873                 g_free(str); \
3874                 DebugLog(("\tFreeing val_str [%s]\n", val_str)); \
3875                 g_free(val_str); \
3876                 offset += val_len; \
3877         } else { \
3878                 DebugLog(("\tError: invalid parameter value!\n")); \
3879                 proto_tree_add_string(tree, hf, tvb, start, len - start, \
3880                                 InvalidParameterValue(Uppercase, value)); \
3881                 offset = start + len; /* Skip to end of buffer */ \
3882         } \
3883         DebugLog(("parameter with text_string value - END\n"));
3884         
3885
3886 #define parameter_text_value(hf,lowercase,Uppercase,value) \
3887         get_text_string(val_str, tvb, offset, val_len, ok); \
3888         if (ok) { \
3889                 if (is_quoted_string(val_str[0])) { \
3890                         if (is_quoted_string(val_str[val_len-2])) { \
3891                                 /* Trailing quote - issue a warning */ \
3892                                 str = g_strdup_printf("%s" TrailingQuoteWarning, val_str); \
3893                                 proto_tree_add_string(tree, hf, \
3894                                                 tvb, start, type_len + val_len, str); \
3895                                 g_free(str); \
3896                                 str = g_strdup_printf("; " lowercase "=%s", val_str); \
3897                         } else { /* OK (no trailing quote) */ \
3898                                 str = g_strdup_printf("%s\"", val_str); \
3899                                 proto_tree_add_string(tree, hf, \
3900                                                 tvb, start, type_len + val_len, str); \
3901                                 g_free(str); \
3902                                 str = g_strdup_printf("; " lowercase "=%s\"", val_str); \
3903                         } \
3904                 } else { /* Token-text | 0x00 */ \
3905                         /* TODO - verify that we have either Token-text or 0x00 */ \
3906                         proto_tree_add_string(tree, hf, \
3907                                         tvb, start, type_len + val_len, val_str); \
3908                         str = g_strdup_printf("; " lowercase "=%s", val_str); \
3909                 } \
3910                 proto_item_append_string(ti, str); \
3911                 g_free(str); \
3912                 g_free(val_str); \
3913                 offset += val_len; \
3914         } else { \
3915                 proto_tree_add_string(tree, hf, tvb, start, len - start, \
3916                                 InvalidParameterValue(Uppercase, value)); \
3917                 offset = start + len; /* Skip to end of buffer */ \
3918         }
3919
3920
3921 /* Parameter = Untyped-parameter | Typed-parameter
3922  * Untyped-parameter = Token-text ( Integer-value | Text-value )
3923  * Typed-parameter =
3924  *              Integer-value (
3925  *                      ( Integer-value | Date-value | Delta-seconds-value
3926  *                        | Q-value | Version-value | Uri-value )
3927  *                      | Text-value )
3928  *
3929  *
3930  * Returns: next offset
3931  *
3932  * TODO - Verify byte highlighting in case of invalid parameter values
3933  */
3934 static int
3935 parameter (proto_tree *tree, proto_item *ti, tvbuff_t *tvb, int start, int len)
3936 {
3937         int offset = start;
3938         guint8 peek = tvb_get_guint8 (tvb,start);
3939         guint32 val = 0, type = 0, type_len, val_len;
3940         gchar *str = NULL;
3941         gchar *val_str = NULL;
3942         gchar *s;
3943         gboolean ok;
3944
3945         DebugLog(("parameter(start = %u, len = %u)\n", start, len));
3946         if (is_token_text (peek)) {
3947                 /*
3948                  * Untyped parameter
3949                  */
3950                 DebugLog(("parameter() - Untyped - Start\n"));
3951                 get_token_text (str,tvb,start,val_len,ok); /* Should always succeed */
3952                 if (ok) { /* Found a textual parameter name: str */
3953                         offset += val_len;
3954                         get_text_value(val_str, tvb, offset, val_len, ok);
3955                         if (ok) { /* Also found a textual parameter value: val_str */
3956                                 DebugLog(("Trying textual parameter value.\n"));
3957                                 offset += val_len;
3958                                 if (is_quoted_string(val_str[0])) { /* Add trailing quote! */
3959                                         if (is_quoted_string(val_str[val_len-2])) {
3960                                                 /* Trailing quote - issue a warning */
3961                                                 proto_tree_add_text(tree, tvb, start, offset - start,
3962                                                                 "%s: %s" TrailingQuoteWarning, str, val_str);
3963                                                 s = g_strdup_printf("; %s=%s", str, val_str);
3964                                         } else { /* OK (no trailing quote) */
3965                                                 proto_tree_add_text(tree, tvb, start, offset - start,
3966                                                                 "%s: %s\"", str, val_str);
3967                                                 s = g_strdup_printf("; %s=%s\"", str, val_str);
3968                                         }
3969                                 } else { /* Token-text | 0x00 */
3970                                         /* TODO - verify that it is either Token-text or 0x00
3971                                          * and flag with warning if invalid */
3972                                         proto_tree_add_text(tree, tvb, start, offset - start,
3973                                                         "%s: %s", str, val_str);
3974                                         s = g_strdup_printf("; %s=%s", str, val_str);
3975                                 }
3976                                 /* TODO - check if we can insert a searchable field in the
3977                                  * protocol tree for the untyped parameter case */
3978                                 DebugLog(("parameter() - Untyped: %s\n", s));
3979                                 proto_item_append_string(ti, s);
3980                                 DebugLog(("Freeing s\n"));
3981                                 g_free(s);
3982                                 DebugLog(("Freeing val_str\n"));
3983                                 g_free(val_str);
3984                                 DebugLog(("Done!\n"));
3985                         } else { /* Try integer value */
3986                                 DebugLog(("Trying integer parameter value.\n"));
3987                                 get_integer_value (val,tvb,offset,val_len,ok);
3988                                 if (ok) { /* Also found a valid integer parameter value: val */
3989                                         offset += val_len;
3990                                         proto_tree_add_text(tree, tvb, start, offset - start,
3991                                                         "%s: %u", str, val);
3992                                         s = g_strdup_printf("; %s=%u", str, val);
3993                                         proto_item_append_string(ti, s);
3994                                         DebugLog(("parameter() - Untyped: %s\n", s));
3995                                         g_free(s);
3996                                         /* TODO - check if we can insert a searchable field in the
3997                                          * protocol tree for the untyped parameter case */
3998                                 } else { /* Error: neither token-text not Integer-value */
3999                                         DebugLog(("Invalid untyped parameter value!\n"));
4000                                         proto_tree_add_text (tree, tvb, start, offset - start,
4001                                                         "<Error: Invalid untyped parameter definition>");
4002                                         offset = start + len; /* Skip to end of buffer */
4003                                 }
4004                         }
4005                         g_free(str);
4006                 }
4007                 DebugLog(("parameter() - Untyped - End\n"));
4008                 return offset;
4009         }
4010         /*
4011          * Else: Typed parameter
4012          */
4013         DebugLog(("parameter() - Typed - Start\n"));
4014         get_integer_value (type,tvb,start,type_len,ok);
4015         if (!ok) {
4016                 proto_tree_add_text (tree, tvb, start, offset - start,
4017                                 "<Error: Invalid typed parameter definition>");
4018                 return (start + len); /* Skip to end of buffer */
4019         }
4020         offset += type_len;
4021         /* Now offset points to the parameter value */
4022         DebugLog(("Typed parameter = 0x%02x\n", type));
4023         switch (type) {
4024                 case 0x01:      /* WSP 1.1 encoding - Charset: Well-known-charset */
4025                         get_integer_value(val, tvb, offset, val_len, ok);
4026                         if (ok) {
4027                                 val_str = val_to_str(val, vals_character_sets,
4028                                                 "<Unknown character set Identifier 0x%X>");
4029                                 proto_tree_add_string(tree, hf_parameter_charset,
4030                                                 tvb, start, type_len + val_len, val_str);
4031                                 str = g_strdup_printf("; charset=%s", val_str);
4032                                 proto_item_append_string(ti, str);
4033                                 g_free(str);
4034                                 offset += val_len;
4035                         } else {
4036                                 proto_tree_add_text (tree, tvb, start, offset,
4037                                                 InvalidParameterValue("Charset", "Integer-value"));
4038                                 offset = start + len; /* Skip to end of buffer */
4039                         }
4040                         break;
4041
4042                 case 0x03:      /* WSP 1.1 encoding - Type: Integer-value */
4043                         get_integer_value (val,tvb,offset,val_len,ok);
4044                         if (ok) {
4045                                 proto_tree_add_uint (tree, hf_wsp_parameter_type,
4046                                                 tvb, start, type_len + val_len, val);
4047                                 s = g_strdup_printf("; Type=%u", val);
4048                                 proto_item_append_string (ti, s);
4049                                 g_free(s);
4050                                 offset += val_len;
4051                         } else {
4052                                 proto_tree_add_text (tree, tvb, start, offset,
4053                                                 InvalidParameterValue("Type", "Integer-value"));
4054                                 offset = start + len; /* Skip to end of buffer */
4055                         }
4056                         break;
4057
4058                 case 0x05:      /* WSP 1.1 encoding - Name: Text-string */
4059                         parameter_text(hf_wsp_parameter_name, "name",
4060                                         "Name (WSP 1.1 encoding)", "Text-string");
4061                         break;
4062                 case 0x17:      /* WSP 1.4 encoding - Name: Text-value */
4063                         parameter_text_value(hf_wsp_parameter_name, "name",
4064                                         "Name (WSP 1.4 encoding)", "Text-value");
4065                         break;
4066
4067                 case 0x06:      /* WSP 1.1 encoding - Filename: Text-string */
4068                         parameter_text(hf_wsp_parameter_filename, "filename",
4069                                         "Filename (WSP 1.1 encoding)", "Text-string");
4070                         break;
4071                 case 0x18:      /* WSP 1.4 encoding - Filename: Text-value */
4072                         parameter_text_value(hf_wsp_parameter_filename, "filename",
4073                                         "Filename (WSP 1.4 encoding)", "Text-value");
4074                         break;
4075
4076                 case 0x09:      /* WSP 1.2 encoding - Type (special): Constrained-encoding */
4077                         /* This is similar to the Content-Type header decoding,
4078                          * but it is much simpler:
4079                          * Constrained-encoding = Short-integer | Extension-media
4080                          * Extension-media = *TEXT <Octet 0>
4081                          */
4082                         get_extension_media(val_str,tvb,offset,val_len,ok);
4083                         if (ok) { /* Extension-media */
4084                                 offset += val_len;
4085                         } else {
4086                                 get_short_integer(val,tvb,offset,val_len,ok);
4087                                 if (ok) {
4088                                         offset += val_len;
4089                                         val_str = val_to_str(val, vals_content_types,
4090                                                         "(Unknown content type identifier 0x%X)");
4091                                 } /* Else: invalid parameter value */
4092                         }
4093                         if (ok) {
4094                                 proto_tree_add_string (tree, hf_wsp_parameter_upart_type,
4095                                                 tvb, start, offset - start, val_str);
4096                                 str = g_strdup_printf("; type=%s", val_str);
4097                                 proto_item_append_string(ti, str);
4098                                 g_free(str);
4099                         } else { /* Invalid parameter value */
4100                                 proto_tree_add_text (tree, tvb, start, len - start,
4101                                                 InvalidParameterValue("Type",
4102                                                         "Constrained-encoding"));
4103                                 offset = start + len; /* Skip the parameters */
4104                         }
4105                         break;
4106
4107                 case 0x0A:      /* WSP 1.2 encoding - Start: Text-string */
4108                         parameter_text(hf_wsp_parameter_start, "start",
4109                                         "Start (WSP 1.2 encoding)", "Text-string");
4110                         break;
4111                 case 0x19:      /* WSP 1.4 encoding - Start (with multipart/related): Text-value */
4112                         parameter_text_value(hf_wsp_parameter_start, "start",
4113                                         "Start (WSP 1.4 encoding)", "Text-value");
4114                         break;
4115
4116                 case 0x0B:      /* WSP 1.2 encoding - Start-info: Text-string */
4117                         parameter_text(hf_wsp_parameter_start_info, "start-info",
4118                                         "Start-info (WSP 1.2 encoding)", "Text-string");
4119                         break;
4120                 case 0x1A:      /* WSP 1.4 encoding - Start-info (with multipart/related): Text-value */
4121                         parameter_text_value(hf_wsp_parameter_start_info, "start-info",
4122                                         "Start-info (WSP 1.4 encoding)", "Text-value");
4123                         break;
4124
4125                 case 0x0C:      /* WSP 1.3 encoding - Comment: Text-string */
4126                         parameter_text(hf_wsp_parameter_comment, "comment",
4127                                         "Comment (WSP 1.3 encoding)", "Text-string");
4128                         break;
4129                 case 0x1B:      /* WSP 1.4 encoding - Comment: Text-value */
4130                         parameter_text_value(hf_wsp_parameter_comment, "comment",
4131                                         "Comment (WSP 1.4 encoding)", "Text-value");
4132                         break;
4133
4134                 case 0x0D:      /* WSP 1.3 encoding - Domain: Text-string */
4135                         parameter_text(hf_wsp_parameter_domain, "domain",
4136                                         "Domain (WSP 1.3 encoding)", "Text-string");
4137                         break;
4138                 case 0x1C:      /* WSP 1.4 encoding - Domain: Text-value */
4139                         parameter_text_value(hf_wsp_parameter_domain, "domain",
4140                                         "Domain (WSP 1.4 encoding)", "Text-value");
4141                         break;
4142
4143                 case 0x0F:      /* WSP 1.3 encoding - Path: Text-string */
4144                         parameter_text(hf_wsp_parameter_path, "path",
4145                                         "Path (WSP 1.3 encoding)", "Text-string");
4146                         break;
4147                 case 0x1D:      /* WSP 1.4 encoding - Path: Text-value */
4148                         parameter_text_value(hf_wsp_parameter_path, "path",
4149                                         "Path (WSP 1.4 encoding)", "Text-value");
4150                         break;
4151
4152                 case 0x11:      /* WSP 1.4 encoding - SEC: Short-integer (OCTET) */
4153                         peek = tvb_get_guint8 (tvb, start+1);
4154                         if (peek & 0x80) { /* Valid Short-integer */
4155                                 peek &= 0x7F;
4156                                 proto_tree_add_uint (tree, hf_wsp_parameter_sec,
4157                                                 tvb, start, 2, peek);
4158                                 str = match_strval(peek, vals_wsp_parameter_sec);
4159                                 proto_item_append_text (ti, "; SEC=%s", str);
4160                                 offset++;
4161                         } else { /* Error */
4162                                 proto_tree_add_text (tree, tvb, start, len - start,
4163                                                 InvalidParameterValue("SEC", "Short-integer"));
4164                                 offset = start + len; /* Skip to end of buffer */
4165                         }
4166                         break;
4167
4168                 case 0x12:      /* WSP 1.4 encoding - MAC: Text-value */
4169                         parameter_text_value(hf_wsp_parameter_mac, "MAC",
4170                                         "MAC", "Text-value");
4171                         break;
4172
4173                 case 0x02:      /* WSP 1.1 encoding - Level: Version-value */
4174                         get_version_value(val,str,tvb,offset,val_len,ok);
4175                         if (ok) {
4176                                 proto_tree_add_string (tree, hf_wsp_parameter_level,
4177                                                 tvb, start, type_len + val_len, str);
4178                                 proto_item_append_text (ti, "; level=%s", str);
4179                                 offset += val_len;
4180                         } else {
4181                                 proto_tree_add_text (tree, tvb, start, len - start,
4182                                                 InvalidParameterValue("Level", "Version-value"));
4183                                 offset = start + len; /* Skip to end of buffer */
4184                         }
4185                         break;
4186
4187                 case 0x00:      /* WSP 1.1 encoding - Q: Q-value */
4188                         offset = parameter_value_q(tree, ti, tvb, offset);
4189                         break;
4190
4191                 case 0x07:      /* WSP 1.1 encoding - Differences: Field-name */
4192                 case 0x08:      /* WSP 1.1 encoding - Padding: Short-integer */
4193                 case 0x0E:      /* WSP 1.3 encoding - Max-Age: Delta-seconds-value */
4194                 case 0x10:      /* WSP 1.3 encoding - Secure: No-value */
4195                 case 0x13:      /* WSP 1.4 encoding - Creation-date: Date-value */
4196                 case 0x14:      /* WSP 1.4 encoding - Modification-date: Date-value */
4197                 case 0x15:      /* WSP 1.4 encoding - Read-date: Date-value */
4198                 case 0x16:      /* WSP 1.4 encoding - Size: Integer-value */
4199                 default:
4200                         DebugLog(("Skipping remaining parameters from here\n"));
4201                         proto_tree_add_text(tree, tvb, start, len - start, 
4202                                         "Undecoded parameter type 0x%02x - decoding stopped",
4203                                         type);
4204                         offset = start + len; /* Skip the parameters */
4205                         break;
4206         }
4207         DebugLog(("parameter() - Typed - End\n"));
4208         return offset;
4209 }
4210
4211
4212 /*
4213  * Dissects the Q-value parameter value.
4214  * 
4215  * Returns: next offset
4216  */
4217 static int
4218 parameter_value_q (proto_tree *tree, proto_item *ti, tvbuff_t *tvb, int start)
4219 {
4220         int offset = start;
4221         guint32 val = 0, val_len;
4222         gchar *str = NULL;
4223         guint8 ok;
4224
4225         get_uintvar_integer (val, tvb, offset, val_len, ok);
4226         if (ok && (val < 1100)) {
4227                 if (val <= 100) { /* Q-value in 0.01 steps */
4228                         str = g_strdup_printf("0.%02u", val - 1);
4229                 } else { /* Q-value in 0.001 steps */
4230                         str = g_strdup_printf("0.%03u", val - 100);
4231                 }
4232                 proto_item_append_text (ti, "; q=%s", str);
4233                 proto_tree_add_string (tree, hf_parameter_q,
4234                                 tvb, start, val_len, str);
4235                 g_free(str);
4236                 offset += val_len;
4237         } else {
4238                 proto_tree_add_text (tree, tvb, start, offset,
4239                                 InvalidParameterValue("Q", "Q-value"));
4240                 offset += val_len;
4241         }
4242         return offset;
4243 }
4244
4245
4246 /* Code to actually dissect the packets */
4247
4248 /*
4249  * WSP redirect
4250  */
4251
4252 static void
4253 dissect_redirect(tvbuff_t *tvb, int offset, packet_info *pinfo,
4254     proto_tree *tree, dissector_handle_t dissector_handle)
4255 {
4256         guint8 flags;
4257         proto_item *ti;
4258         proto_tree *addresses_tree;
4259         proto_tree *addr_tree = NULL;
4260         proto_tree *flags_tree;
4261         guint8 bearer_type;
4262         guint8 address_flags_len;
4263         int address_len;
4264         proto_tree *address_flags_tree;
4265         guint16 port_num;
4266         guint32 address_ipv4;
4267         struct e_in6_addr address_ipv6;
4268         address redir_address;
4269         conversation_t *conv;
4270         guint32 index = 0; /* Address index */
4271
4272         /*
4273          * Redirect flags.
4274          */
4275         flags = tvb_get_guint8 (tvb, offset);
4276         if (tree) {
4277                 ti = proto_tree_add_uint (tree, hf_wsp_redirect_flags,
4278                     tvb, offset, 1, flags);
4279                 flags_tree = proto_item_add_subtree (ti, ett_redirect_flags);
4280                 proto_tree_add_boolean (flags_tree, hf_wsp_redirect_permanent,
4281                     tvb, offset, 1, flags);
4282                 proto_tree_add_boolean (flags_tree, hf_wsp_redirect_reuse_security_session,
4283                     tvb, offset, 1, flags);
4284         }
4285         offset++;
4286
4287         /*
4288          * Redirect addresses.
4289          */
4290         ti = proto_tree_add_item(tree, hf_redirect_addresses, tvb, 0, -1, bo_little_endian);
4291         addresses_tree = proto_item_add_subtree(ti, ett_addresses);
4292
4293         while (tvb_reported_length_remaining (tvb, offset) > 0) {
4294                 index++;
4295                 /*
4296                  * Read a single address at a time.
4297                  */
4298                 address_flags_len = tvb_get_guint8 (tvb, offset);
4299                 address_len = address_flags_len & ADDRESS_LEN;
4300                 if (tree) {
4301
4302                         ti = proto_tree_add_uint(addresses_tree, hf_address_entry,
4303                                         tvb, offset, 1 + address_len, index);
4304                         addr_tree = proto_item_add_subtree(ti, ett_address);
4305
4306                         ti = proto_tree_add_uint (addr_tree, hf_address_flags_length,
4307                             tvb, offset, 1, address_flags_len);
4308                         address_flags_tree = proto_item_add_subtree (ti, ett_address_flags);
4309                         proto_tree_add_boolean (address_flags_tree, hf_address_flags_length_bearer_type_included,
4310                             tvb, offset, 1, address_flags_len);
4311                         proto_tree_add_boolean (address_flags_tree, hf_address_flags_length_port_number_included,
4312                             tvb, offset, 1, address_flags_len);
4313                         proto_tree_add_uint (address_flags_tree, hf_address_flags_length_address_len,
4314                             tvb, offset, 1, address_flags_len);
4315                 }
4316                 offset++;
4317                 if (address_flags_len & BEARER_TYPE_INCLUDED) {
4318                         bearer_type = tvb_get_guint8 (tvb, offset);
4319                         if (tree) {
4320                                 proto_tree_add_uint (addr_tree, hf_address_bearer_type,
4321                                     tvb, offset, 1, bearer_type);
4322                         }
4323                         offset++;
4324                 } else {
4325                         bearer_type = 0x00;     /* XXX */
4326                 }
4327                 if (address_flags_len & PORT_NUMBER_INCLUDED) {
4328                         port_num = tvb_get_ntohs (tvb, offset);
4329                         if (tree) {
4330                                 proto_tree_add_uint (addr_tree, hf_address_port_num,
4331                                     tvb, offset, 2, port_num);
4332                         }
4333                         offset += 2;
4334                 } else {
4335                         /*
4336                          * Redirecting to the same server port number as was
4337                          * being used, i.e. the source port number of this
4338                          * redirect.
4339                          */
4340                         port_num = pinfo->srcport;
4341                 }
4342                 if (!(address_flags_len & BEARER_TYPE_INCLUDED)) {
4343                         /*
4344                          * We don't have the bearer type in the message,
4345                          * so we don't know the address type.
4346                          * (It's the same bearer type as the original
4347                          * connection.)
4348                          */
4349                         goto unknown_address_type;
4350                 }
4351
4352                 /*
4353                  * We know the bearer type, so we know the address type.
4354                  */
4355                 switch (bearer_type) {
4356
4357                 case BT_IPv4:
4358                 case BT_IS_95_CSD:
4359                 case BT_IS_95_PACKET_DATA:
4360                 case BT_ANSI_136_CSD:
4361                 case BT_ANSI_136_PACKET_DATA:
4362                 case BT_GSM_CSD:
4363                 case BT_GSM_GPRS:
4364                 case BT_GSM_USSD_IPv4:
4365                 case BT_AMPS_CDPD:
4366                 case BT_PDC_CSD:
4367                 case BT_PDC_PACKET_DATA:
4368                 case BT_IDEN_CSD:
4369                 case BT_IDEN_PACKET_DATA:
4370                 case BT_PHS_CSD:
4371                 case BT_TETRA_PACKET_DATA:
4372                         /*
4373                          * IPv4.
4374                          */
4375                         if (address_len != 4) {
4376                                 /*
4377                                  * Say what?
4378                                  */
4379                                 goto unknown_address_type;
4380                         }
4381                         tvb_memcpy(tvb, (guint8 *)&address_ipv4, offset, 4);
4382                         if (tree) {
4383                                 proto_tree_add_ipv4 (addr_tree,
4384                                     hf_address_ipv4_addr,
4385                                     tvb, offset, 4, address_ipv4);
4386                         }
4387
4388                         /*
4389                          * Create a conversation so that the
4390                          * redirected session will be dissected
4391                          * as WAP.
4392                          */
4393                         redir_address.type = AT_IPv4;
4394                         redir_address.len = 4;
4395                         redir_address.data = (const guint8 *)&address_ipv4;
4396                         conv = find_conversation(&redir_address, &pinfo->dst,
4397                             PT_UDP, port_num, 0, NO_PORT_B);
4398                         if (conv == NULL) {
4399                                 conv = conversation_new(&redir_address,
4400                                     &pinfo->dst, PT_UDP, port_num, 0, NO_PORT2);
4401                         }
4402                         conversation_set_dissector(conv, dissector_handle);
4403                         break;
4404
4405                 case BT_IPv6:
4406                         /*
4407                          * IPv6.
4408                          */
4409                         if (address_len != 16) {
4410                                 /*
4411                                  * Say what?
4412                                  */
4413                                 goto unknown_address_type;
4414                         }
4415                         tvb_memcpy(tvb, (guint8 *)&address_ipv6, offset, 16);
4416                         if (tree) {
4417                                 proto_tree_add_ipv6 (addr_tree,
4418                                     hf_address_ipv6_addr,
4419                                     tvb, offset, 16, (guint8 *)&address_ipv6);
4420                         }
4421
4422                         /*
4423                          * Create a conversation so that the
4424                          * redirected session will be dissected
4425                          * as WAP.
4426                          */
4427                         redir_address.type = AT_IPv6;
4428                         redir_address.len = 16;
4429                         redir_address.data = (const guint8 *)&address_ipv4;
4430                         conv = find_conversation(&redir_address, &pinfo->dst,
4431                             PT_UDP, port_num, 0, NO_PORT_B);
4432                         if (conv == NULL) {
4433                                 conv = conversation_new(&redir_address,
4434                                     &pinfo->dst, PT_UDP, port_num, 0, NO_PORT2);
4435                         }
4436                         conversation_set_dissector(conv, dissector_handle);
4437                         break;
4438
4439                 unknown_address_type:
4440                 default:
4441                         if (address_len != 0) {
4442                                 if (tree) {
4443                                         proto_tree_add_item (addr_tree, hf_address_addr,
4444                                                         tvb, offset, address_len, bo_little_endian);
4445                                 }
4446                         }
4447                         break;
4448                 }
4449                 offset += address_len;
4450         } /* while */
4451 }
4452
4453 static void
4454 add_addresses(proto_tree *tree, tvbuff_t *tvb, int hf)
4455 {
4456         proto_item *ti;
4457         proto_tree *addresses_tree;
4458         proto_tree *addr_tree;
4459         guint8 bearer_type;
4460         guint8 address_flags_len;
4461         int address_len;
4462         proto_tree *address_flags_tree;
4463         guint16 port_num;
4464         guint32 address_ipv4;
4465         struct e_in6_addr address_ipv6;
4466         guint32 tvb_len = tvb_length(tvb);
4467         guint32 offset = 0;
4468         guint32 index = 0; /* Address index */
4469
4470         /* Skip needless processing */
4471         if (! tree)
4472                 return;
4473         if (offset >= tvb_len)
4474                 return;
4475
4476         /*
4477          * Addresses.
4478          */
4479         ti = proto_tree_add_item(tree, hf, tvb, 0, -1, bo_little_endian);
4480         addresses_tree = proto_item_add_subtree(ti, ett_addresses);
4481
4482         while (offset < tvb_len) {
4483                 index++;
4484                 /*
4485                  * Read a single address at a time.
4486                  */
4487                 address_flags_len = tvb_get_guint8 (tvb, offset);
4488                 address_len = address_flags_len & ADDRESS_LEN;
4489
4490                 ti = proto_tree_add_uint(addresses_tree, hf_address_entry,
4491                                 tvb, offset, 1 + address_len, index);
4492                 addr_tree = proto_item_add_subtree(ti, ett_address);
4493
4494                 ti = proto_tree_add_uint (addr_tree, hf_address_flags_length,
4495                                 tvb, offset, 1, address_flags_len);
4496                 address_flags_tree = proto_item_add_subtree (ti, ett_address_flags);
4497                 proto_tree_add_boolean (address_flags_tree, hf_address_flags_length_bearer_type_included,
4498                                 tvb, offset, 1, address_flags_len);
4499                 proto_tree_add_boolean (address_flags_tree, hf_address_flags_length_port_number_included,
4500                                 tvb, offset, 1, address_flags_len);
4501                 proto_tree_add_uint (address_flags_tree, hf_address_flags_length_address_len,
4502                                 tvb, offset, 1, address_flags_len);
4503                 offset++;
4504                 if (address_flags_len & BEARER_TYPE_INCLUDED) {
4505                         bearer_type = tvb_get_guint8 (tvb, offset);
4506                         proto_tree_add_uint (addr_tree, hf_address_bearer_type,
4507                                         tvb, offset, 1, bearer_type);
4508                         offset++;
4509                 } else {
4510                         bearer_type = 0x00;     /* XXX */
4511                 }
4512                 if (address_flags_len & PORT_NUMBER_INCLUDED) {
4513                         port_num = tvb_get_ntohs (tvb, offset);
4514                                 proto_tree_add_uint (addr_tree, hf_address_port_num,
4515                                                 tvb, offset, 2, port_num);
4516                         offset += 2;
4517                 } else {
4518                         /*
4519                          * Redirecting to the same server port number as was
4520                          * being used, i.e. the source port number of this
4521                          * redirect.
4522                          */
4523                         port_num = 0;
4524                 }
4525                 if (!(address_flags_len & BEARER_TYPE_INCLUDED)) {
4526                         /*
4527                          * We don't have the bearer type in the message,
4528                          * so we don't know the address type.
4529                          * (It's the same bearer type as the original
4530                          * connection.)
4531                          */
4532                         goto unknown_address_type;
4533                 }
4534
4535                 /*
4536                  * We know the bearer type, so we know the address type.
4537                  */
4538                 switch (bearer_type) {
4539
4540                 case BT_IPv4:
4541                 case BT_IS_95_CSD:
4542                 case BT_IS_95_PACKET_DATA:
4543                 case BT_ANSI_136_CSD:
4544                 case BT_ANSI_136_PACKET_DATA:
4545                 case BT_GSM_CSD:
4546                 case BT_GSM_GPRS:
4547                 case BT_GSM_USSD_IPv4:
4548                 case BT_AMPS_CDPD:
4549                 case BT_PDC_CSD:
4550                 case BT_PDC_PACKET_DATA:
4551                 case BT_IDEN_CSD:
4552                 case BT_IDEN_PACKET_DATA:
4553                 case BT_PHS_CSD:
4554                 case BT_TETRA_PACKET_DATA:
4555                         /*
4556                          * IPv4.
4557                          */
4558                         if (address_len != 4) {
4559                                 /*
4560                                  * Say what?
4561                                  */
4562                                 goto unknown_address_type;
4563                         }
4564                         tvb_memcpy(tvb, (guint8 *)&address_ipv4, offset, 4);
4565                         proto_tree_add_ipv4 (addr_tree, hf_address_ipv4_addr,
4566                                         tvb, offset, 4, address_ipv4);
4567                         break;
4568
4569                 case BT_IPv6:
4570                         /*
4571                          * IPv6.
4572                          */
4573                         if (address_len != 16) {
4574                                 /*
4575                                  * Say what?
4576                                  */
4577                                 goto unknown_address_type;
4578                         }
4579                         tvb_memcpy(tvb, (guint8 *)&address_ipv6, offset, 16);
4580                         proto_tree_add_ipv6 (addr_tree, hf_address_ipv6_addr,
4581                                         tvb, offset, 16, (guint8 *)&address_ipv6);
4582                         break;
4583
4584                 unknown_address_type:
4585                 default:
4586                         if (address_len != 0) {
4587                                 proto_tree_add_item (addr_tree, hf_address_addr,
4588                                                 tvb, offset, address_len, bo_little_endian);
4589                         }
4590                         break;
4591                 }
4592                 offset += address_len;
4593         } /* while */
4594 }
4595
4596 static const value_string vals_sir_protocol_options[] = {
4597         { 0, "OTA-HTTP, no CPITag present" },
4598         { 1, "OTA-HTTP, CPITag present" },
4599         /* 2--255 are reserved */
4600         /* 256--16383 are available for private WINA registration */
4601
4602         { 0x00, NULL }
4603 };
4604
4605 /*
4606  * Dissect a Session Initiation Request.
4607  *
4608  * Arguably this should be a separate dissector, but SIR does not make sense
4609  * outside of WSP anyway.
4610  */
4611 static void
4612 dissect_sir(proto_tree *tree, tvbuff_t *tvb)
4613 {
4614         guint8 version;
4615         guint32 val_len;
4616         guint32 len;
4617         guint32 offset = 0;
4618         guint32 i;
4619         tvbuff_t *tmp_tvb;
4620         proto_tree *subtree;
4621         proto_item *ti;
4622
4623         if (! tree)
4624                 return;
4625
4626         ti = proto_tree_add_item(tree, hf_sir_section,
4627                         tvb, 0, -1, bo_little_endian);
4628         subtree = proto_item_add_subtree(ti, ett_sir);
4629         
4630         /* Version */
4631         version = tvb_get_guint8(tvb, 0);
4632         proto_tree_add_uint(subtree, hf_sir_version,
4633                         tvb, 0, 1, version);
4634
4635         /* Length of Application-Id headers list */
4636         val_len = tvb_get_guintvar(tvb, 1, &len);
4637         proto_tree_add_uint(subtree, hf_sir_app_id_list_len,
4638                         tvb, 1, len, val_len);
4639         offset = 1 + len;
4640         /* Application-Id headers */
4641         tmp_tvb = tvb_new_subset(tvb, offset, val_len, val_len);
4642         add_headers (subtree, tmp_tvb, hf_sir_app_id_list);
4643         offset += val_len;
4644
4645         /* Length of WSP contact points list */
4646         val_len = tvb_get_guintvar(tvb, offset, &len);
4647         proto_tree_add_uint(subtree, hf_sir_wsp_contact_points_len,
4648                         tvb, offset, len, val_len);
4649         offset += len;
4650         /* WSP contact point list */
4651         tmp_tvb = tvb_new_subset (tvb, offset, val_len, val_len);
4652         add_addresses(subtree, tmp_tvb, hf_sir_wsp_contact_points);
4653         g_free(tmp_tvb);
4654
4655         /* End of version 0 SIR content */
4656         if (version == 0)
4657                 return;
4658
4659         /* Length of non-WSP contact points list */
4660         val_len = tvb_get_guintvar(tvb, offset, &len);
4661         proto_tree_add_uint(subtree, hf_sir_contact_points_len,
4662                         tvb, offset, len, val_len);
4663         offset += len;
4664         /* Non-WSP contact point list */
4665         tmp_tvb = tvb_new_subset (tvb, offset, val_len, val_len);
4666         add_addresses(subtree, tmp_tvb, hf_sir_contact_points);
4667         g_free(tmp_tvb);
4668
4669         /* Number of entries in the Protocol Options list */
4670         val_len = tvb_get_guintvar(tvb, offset, &len);
4671         proto_tree_add_uint(subtree, hf_sir_protocol_options_len,
4672                         tvb, offset, len, val_len);
4673         offset += len;
4674         /* Protocol Options list.
4675          * Each protocol option is encoded as a guintvar */
4676         for (i = 0; i < val_len; i++) {
4677                 val_len = tvb_get_guintvar(tvb, offset, &len);
4678                 proto_tree_add_uint(subtree, hf_sir_protocol_options,
4679                                 tvb, offset, len, val_len);
4680                 offset += len;
4681         }
4682
4683         /* Length of ProvURL */
4684         val_len = tvb_get_guintvar(tvb, offset, &len);
4685         proto_tree_add_uint(subtree, hf_sir_prov_url_len,
4686                         tvb, offset, len, val_len);
4687         offset += len;
4688         /* ProvURL */
4689         tvb_ensure_bytes_exist(tvb, offset, val_len);
4690         ti = proto_tree_add_item (tree, hf_sir_prov_url,
4691                         tvb, offset, val_len, bo_little_endian);
4692         offset += val_len;
4693
4694         /* Number of entries in the CPITag list */
4695         val_len = tvb_get_guintvar(tvb, offset, &len);
4696         proto_tree_add_uint(subtree, hf_sir_cpi_tag_len,
4697                         tvb, offset, len, val_len);
4698         offset += len;
4699         /* CPITag list.
4700          * Each CPITag is encoded as 4 octets of opaque data.
4701          * In OTA-HTTP, it is conveyed in the X-Wap-CPITag header
4702          * but with a Base64 encoding of the 4 bytes. */
4703         for (i = 0; i < val_len; i++) {
4704                 val_len = tvb_get_guintvar(tvb, offset, &len);
4705                 proto_tree_add_item(subtree, hf_sir_cpi_tag,
4706                                 tvb, offset, 4, val_len);
4707                 offset += 4;
4708         }
4709 }
4710
4711 static void
4712 dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
4713     dissector_handle_t dissector_handle, gboolean is_connectionless)
4714 {
4715         int offset = 0;
4716
4717         guint8 pdut;
4718         guint8 reply_status;
4719         guint count = 0;
4720         guint value = 0;
4721         guint uriLength = 0;
4722         guint uriStart = 0;
4723         guint capabilityLength = 0;
4724         guint capabilityStart = 0;
4725         guint headersLength = 0;
4726         guint headerLength = 0;
4727         guint headerStart = 0;
4728         guint nextOffset = 0;
4729         guint contentTypeStart = 0;
4730         guint contentType = 0;
4731         const char *contentTypeStr;
4732         tvbuff_t *tmp_tvb;
4733         gboolean found_match;
4734
4735 /* Set up structures we will need to add the protocol subtree and manage it */
4736         proto_item *ti;
4737         proto_tree *wsp_tree = NULL;
4738
4739         wsp_info_value_t *stat_info;
4740         stat_info = g_malloc( sizeof(wsp_info_value_t) );
4741         stat_info->status_code = 0;
4742
4743 /* This field shows up as the "Info" column in the display; you should make
4744    it, if possible, summarize what's in the packet, so that a user looking
4745    at the list of packets can tell what type of packet it is. */
4746
4747         /* Connection-less mode has a TID first */
4748         if (is_connectionless)
4749         {
4750                 offset++; /* Skip the 1-byte Transaction ID */
4751         };
4752
4753         /* Find the PDU type */
4754         pdut = tvb_get_guint8 (tvb, offset);
4755
4756         /* Develop the string to put in the Info column */
4757         if (check_col(pinfo->cinfo, COL_INFO))
4758         {
4759                 col_append_fstr(pinfo->cinfo, COL_INFO, "WSP %s",
4760                         val_to_str (pdut, vals_pdu_type, "Unknown PDU type (0x%02x)"));
4761         };
4762
4763         /* In the interest of speed, if "tree" is NULL, don't do any work not
4764          * necessary to generate protocol tree items. */
4765         if (tree) {
4766                 ti = proto_tree_add_item(tree, proto_wsp,
4767                                 tvb, 0, -1, bo_little_endian);
4768                 wsp_tree = proto_item_add_subtree(ti, ett_wsp);
4769
4770                 /* Add common items: only TID and PDU Type */
4771
4772                 /* If this is connectionless, then the TID Field is always first */
4773                 if (is_connectionless)
4774                 {
4775                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_tid,
4776                                         tvb, 0, 1, bo_little_endian);
4777                 }
4778                 ti = proto_tree_add_item( wsp_tree, hf_wsp_header_pdu_type,
4779                                 tvb, offset, 1, bo_little_endian);
4780         }
4781         offset++;
4782
4783         /* Map extended methods to the main method now the Column info has been
4784          * written; this way we can dissect the extended method PDUs. */
4785         if ((pdut >= 0x50) && (pdut <= 0x5F)) /* Extended GET --> GET */
4786                 pdut = WSP_PDU_GET;
4787         else if ((pdut >= 0x70) && (pdut <= 0x7F)) /* Extended POST --> POST */
4788                 pdut = WSP_PDU_POST;
4789
4790         switch (pdut)
4791         {
4792                 case WSP_PDU_CONNECT:
4793                 case WSP_PDU_CONNECTREPLY:
4794                 case WSP_PDU_RESUME:
4795                         if (tree) {
4796                                 if (pdut == WSP_PDU_CONNECT)
4797                                 {
4798                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,
4799                                                         tvb, offset, 1, bo_little_endian);
4800                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,
4801                                                         tvb, offset, 1, bo_little_endian);
4802                                         offset++;
4803                                 } else {
4804                                         count = 0;      /* Initialise count */
4805                                         value = tvb_get_guintvar (tvb, offset, &count);
4806                                         ti = proto_tree_add_uint (wsp_tree,
4807                                                         hf_wsp_server_session_id,
4808                                                         tvb, offset, count, value);
4809                                         offset += count;
4810                                 }
4811                                 capabilityStart = offset;
4812                                 count = 0;      /* Initialise count */
4813                                 capabilityLength = tvb_get_guintvar (tvb, offset, &count);
4814                                 offset += count;
4815                                 ti = proto_tree_add_uint (wsp_tree, hf_capabilities_length,
4816                                                 tvb, capabilityStart, count, capabilityLength);
4817
4818                                 if (pdut != WSP_PDU_RESUME)
4819                                 {
4820                                         count = 0;      /* Initialise count */
4821                                         headerLength = tvb_get_guintvar (tvb, offset, &count);
4822                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,
4823                                                         tvb, offset, count, headerLength);
4824                                         offset += count;
4825                                         capabilityStart = offset;
4826                                         headerStart = capabilityStart + capabilityLength;
4827                                 } else {
4828                                                 /* Resume computes the headerlength
4829                                                  * by remaining bytes */
4830                                         capabilityStart = offset;
4831                                         headerStart = capabilityStart + capabilityLength;
4832                                         headerLength = tvb_reported_length_remaining (tvb,
4833                                                         headerStart);
4834                                 }
4835                                 if (capabilityLength > 0)
4836                                 {
4837                                         tmp_tvb = tvb_new_subset (tvb, offset,
4838                                                         capabilityLength, capabilityLength);
4839                                         add_capabilities (wsp_tree, tmp_tvb, pdut);
4840                                         offset += capabilityLength;
4841                                 }
4842
4843                                 if (headerLength > 0)
4844                                 {
4845                                         tmp_tvb = tvb_new_subset (tvb, offset,
4846                                                         headerLength, headerLength);
4847                                         add_headers (wsp_tree, tmp_tvb, hf_wsp_headers_section);
4848                                 }
4849                         }
4850
4851                         break;
4852
4853                 case WSP_PDU_REDIRECT:
4854                         dissect_redirect(tvb, offset, pinfo, wsp_tree, dissector_handle);
4855                         break;
4856
4857                 case WSP_PDU_DISCONNECT:
4858                 case WSP_PDU_SUSPEND:
4859                         if (tree) {
4860                                 count = 0;      /* Initialise count */
4861                                 value = tvb_get_guintvar (tvb, offset, &count);
4862                                 ti = proto_tree_add_uint (wsp_tree,
4863                                                 hf_wsp_server_session_id,
4864                                                 tvb, offset, count, value);
4865                         }
4866                         break;
4867
4868                 case WSP_PDU_GET:
4869                         count = 0;      /* Initialise count */
4870                         /* Length of URI and size of URILen field */
4871                         value = tvb_get_guintvar (tvb, offset, &count);
4872                         nextOffset = offset + count;
4873                         add_uri (wsp_tree, pinfo, tvb, offset, nextOffset);
4874                         if (tree) {
4875                                 offset += value + count; /* VERIFY */
4876                                 tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
4877                                 add_headers (wsp_tree, tmp_tvb, hf_wsp_headers_section);
4878                         }
4879                         break;
4880
4881                 case WSP_PDU_POST:
4882                         uriStart = offset;
4883                         count = 0;      /* Initialise count */
4884                         uriLength = tvb_get_guintvar (tvb, offset, &count);
4885                         headerStart = uriStart+count;
4886                         count = 0;      /* Initialise count */
4887                         headersLength = tvb_get_guintvar (tvb, headerStart, &count);
4888                         offset = headerStart + count;
4889
4890                         add_uri (wsp_tree, pinfo, tvb, uriStart, offset);
4891                         offset += uriLength;
4892
4893                         if (tree)
4894                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,
4895                                                 tvb, headerStart, count, headersLength);
4896
4897                         if (headersLength == 0)
4898                                 break;
4899
4900                         contentTypeStart = offset;
4901                         nextOffset = add_content_type (wsp_tree,
4902                                         tvb, offset, &contentType, &contentTypeStr);
4903
4904                         if (tree) {
4905                                 /* Add headers subtree that will hold the headers fields */
4906                                 /* Runs from nextOffset for
4907                                  * headersLength - (length of content-type field) */
4908                                 headerLength = headersLength - (nextOffset - contentTypeStart);
4909                                 if (headerLength > 0)
4910                                 {
4911                                         tmp_tvb = tvb_new_subset (tvb, nextOffset,
4912                                                         headerLength, headerLength);
4913                                         add_headers (wsp_tree, tmp_tvb, hf_wsp_headers_section);
4914                                 }
4915                                 offset = nextOffset+headerLength;
4916                         }
4917                         /* WSP_PDU_POST data - First check whether a subdissector exists
4918                          * for the content type */
4919                         if (tvb_reported_length_remaining(tvb,
4920                                                 headerStart + count + uriLength + headersLength) > 0)
4921                         {
4922                                 tmp_tvb = tvb_new_subset (tvb,
4923                                                 headerStart + count + uriLength + headersLength,
4924                                                 -1, -1);
4925                                 /*
4926                                  * Try finding a dissector for the content
4927                                  * first, then fallback.
4928                                  */
4929                                 found_match = FALSE;
4930                                 if (contentTypeStr) {
4931                                         /*
4932                                          * Content type is a string.
4933                                          */
4934                                         found_match = dissector_try_string(media_type_table,
4935                                                         contentTypeStr, tmp_tvb, pinfo, tree);
4936                                 }
4937                                 if (! found_match) {
4938                                         if (! dissector_try_heuristic(heur_subdissector_list,
4939                                                                 tmp_tvb, pinfo, tree))
4940                                                 if (tree) /* Only display if needed */
4941                                                         add_post_data (wsp_tree, tmp_tvb,
4942                                                                         contentType, contentTypeStr);
4943                                 }
4944                         }
4945                         break;
4946
4947                 case WSP_PDU_REPLY:
4948                         count = 0;      /* Initialise count */
4949                         headersLength = tvb_get_guintvar (tvb, offset+1, &count);
4950                         headerStart = offset + count + 1;
4951                         reply_status = tvb_get_guint8(tvb, offset);
4952                         if (tree)
4953                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,
4954                                                 tvb, offset, 1, bo_little_endian);
4955                         stat_info->status_code = (gint) tvb_get_guint8(tvb, offset);                            
4956                         if (check_col(pinfo->cinfo, COL_INFO))
4957                         { /* Append status code to INFO column */
4958                                 col_append_fstr(pinfo->cinfo, COL_INFO,
4959                                                 ": \"0x%02x %s\"", reply_status,
4960                                                 val_to_str (reply_status, vals_status,
4961                                                         "Unknown response status (0x%02x)"));
4962                         }
4963                         nextOffset = offset + 1 + count;
4964                         if (tree)
4965                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,
4966                                                 tvb, offset + 1, count, headersLength);
4967
4968                         if (headersLength == 0)
4969                                 break;
4970
4971                         contentTypeStart = nextOffset;
4972                         nextOffset = add_content_type (wsp_tree, tvb,
4973                                         nextOffset, &contentType, &contentTypeStr);
4974
4975                         if (tree) {
4976                                 /* Add headers subtree that will hold the headers fields */
4977                                 /* Runs from nextOffset for
4978                                  * headersLength - (length of content-type field) */
4979                                 headerLength = headersLength - (nextOffset - contentTypeStart);
4980                                 if (headerLength > 0)
4981                                 {
4982                                         tmp_tvb = tvb_new_subset (tvb, nextOffset,
4983                                                         headerLength, headerLength);
4984                                         add_headers (wsp_tree, tmp_tvb, hf_wsp_headers_section);
4985                                 }
4986                                 offset += count+headersLength+1;
4987                         }
4988                         /* WSP_PDU_REPLY data - First check whether a subdissector exists
4989                          * for the content type */
4990                         if (tvb_reported_length_remaining(tvb, headerStart + headersLength)
4991                                         > 0)
4992                         {
4993                                 tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength,
4994                                                 -1, -1);
4995                                 /*
4996                                  * Try finding a dissector for the content
4997                                  * first, then fallback.
4998                                  */
4999                                 found_match = FALSE;
5000                                 if (contentTypeStr) {
5001                                         /*
5002                                          * Content type is a string.
5003                                          */
5004                                         found_match = dissector_try_string(media_type_table,
5005                                                         contentTypeStr, tmp_tvb, pinfo, tree);
5006                                 }
5007                                 if (! found_match) {
5008                                         if (! dissector_try_heuristic(heur_subdissector_list,
5009                                                                 tmp_tvb, pinfo, tree))
5010                                                 if (tree) /* Only display if needed */
5011                                                         ti = proto_tree_add_item (wsp_tree,
5012                                                             hf_wsp_reply_data,
5013                                                             tmp_tvb, 0, -1, bo_little_endian);
5014                                 }
5015                         }
5016                         break;
5017
5018                 case WSP_PDU_PUSH:
5019                 case WSP_PDU_CONFIRMEDPUSH:
5020                         count = 0;      /* Initialise count */
5021                         headersLength = tvb_get_guintvar (tvb, offset, &count);
5022                         headerStart = offset + count;
5023
5024                         if (tree)
5025                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,
5026                                                 tvb, offset, count, headersLength);
5027
5028                         if (headersLength == 0)
5029                                 break;
5030
5031                         offset += count;
5032                         contentTypeStart = offset;
5033                         nextOffset = add_content_type (wsp_tree,
5034                                         tvb, offset, &contentType, &contentTypeStr);
5035
5036                         if (tree) {
5037                                 /* Add headers subtree that will hold the headers fields */
5038                                 /* Runs from nextOffset for
5039                                  * headersLength-(length of content-type field) */
5040                                 headerLength = headersLength-(nextOffset-contentTypeStart);
5041                                 if (headerLength > 0)
5042                                 {
5043                                         tmp_tvb = tvb_new_subset (tvb, nextOffset,
5044                                                         headerLength, headerLength);
5045                                         add_headers (wsp_tree, tmp_tvb, hf_wsp_headers_section);
5046                                 }
5047                                 offset += headersLength;
5048                         }
5049                         /* WSP_PDU_PUSH data - First check whether a subdissector exists
5050                          * for the content type */
5051                         if (tvb_reported_length_remaining(tvb, headerStart + headersLength)
5052                                         > 0)
5053                         {
5054                                 tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength,
5055                                                 -1, -1);
5056                                 /*
5057                                  * Try finding a dissector for the content
5058                                  * first, then fallback.
5059                                  */
5060                                 found_match = FALSE;
5061                                 if (contentTypeStr) {
5062                                         /*
5063                                          * Content type is a string.
5064                                          */
5065                                         if (strcasecmp(contentTypeStr, "application/vnd.wap.sia") == 0) {
5066                                                 dissect_sir(tree, tmp_tvb);
5067                                         } else
5068                                         found_match = dissector_try_string(media_type_table,
5069                                                         contentTypeStr, tmp_tvb, pinfo, tree);
5070                                 }
5071                                 if (! found_match) {
5072                                         if (! dissector_try_heuristic(heur_subdissector_list,
5073                                                                 tmp_tvb, pinfo, tree))
5074                                                 if (tree) /* Only display if needed */
5075                                                         ti = proto_tree_add_item (wsp_tree,
5076                                                                         hf_wsp_push_data,
5077                                                                         tmp_tvb, 0, -1, bo_little_endian);
5078                                 }
5079                         }
5080                         break;
5081
5082         }
5083         stat_info->pdut = pdut;
5084         tap_queue_packet (wsp_tap, pinfo, stat_info);
5085 }
5086
5087
5088 /*
5089  * Called directly from UDP.
5090  * Put "WSP" into the "Protocol" column.
5091  */
5092 static void
5093 dissect_wsp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5094 {
5095         if (check_col(pinfo->cinfo, COL_PROTOCOL))
5096                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WSP" );
5097         if (check_col(pinfo->cinfo, COL_INFO))
5098                 col_clear(pinfo->cinfo, COL_INFO);
5099
5100         dissect_wsp_common(tvb, pinfo, tree, wsp_fromudp_handle, TRUE);
5101 }
5102
5103
5104 /*
5105  * Called from a higher-level WAP dissector, in connection-oriented mode.
5106  * Leave the "Protocol" column alone - the dissector calling us should
5107  * have set it.
5108  */
5109 static void
5110 dissect_wsp_fromwap_co(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5111 {
5112         /*
5113          * XXX - what about WTLS->WTP->WSP?
5114          */
5115         dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, FALSE);
5116 }
5117
5118
5119 /*
5120  * Called from a higher-level WAP dissector, in connectionless mode.
5121  * Leave the "Protocol" column alone - the dissector calling us should
5122  * have set it.
5123  */
5124 static void
5125 dissect_wsp_fromwap_cl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5126 {
5127         /*
5128          * XXX - what about WTLS->WSP?
5129          */
5130         if (check_col(pinfo->cinfo, COL_INFO))
5131         {
5132                 col_clear(pinfo->cinfo, COL_INFO);
5133         }
5134         dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, TRUE);
5135 }
5136
5137
5138 static void
5139 add_uri (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb,
5140                 guint URILenOffset, guint URIOffset)
5141 {
5142         proto_item *ti;
5143
5144         guint count = 0;
5145         guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
5146
5147         if (tree)
5148                 ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,
5149                                 tvb, URILenOffset, count, uriLen);
5150
5151         tvb_ensure_bytes_exist(tvb, URIOffset, uriLen);
5152         if (tree)
5153                 ti = proto_tree_add_item (tree, hf_wsp_header_uri,
5154                                 tvb, URIOffset, uriLen, bo_little_endian);
5155         if (check_col(pinfo->cinfo, COL_INFO)) {
5156                 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
5157                     tvb_format_text (tvb, URIOffset, uriLen));
5158         }
5159 }
5160
5161
5162 /*
5163  * CO-WSP capability negotiation
5164  */
5165
5166 enum {
5167         WSP_CAPA_CLIENT_SDU_SIZE = 0x00,
5168         WSP_CAPA_SERVER_SDU_SIZE,
5169         WSP_CAPA_PROTOCOL_OPTIONS,
5170         WSP_CAPA_METHOD_MOR,
5171         WSP_CAPA_PUSH_MOR,
5172         WSP_CAPA_EXTENDED_METHODS,
5173         WSP_CAPA_HEADER_CODE_PAGES,
5174         WSP_CAPA_ALIASES,
5175         WSP_CAPA_CLIENT_MESSAGE_SIZE,
5176         WSP_CAPA_SERVER_MESSAGE_SIZE
5177 };
5178
5179 static void
5180 add_capabilities (proto_tree *tree, tvbuff_t *tvb, guint8 pdu_type)
5181 {
5182         proto_tree *wsp_capabilities;
5183         proto_tree *capa_subtree;
5184         proto_item *ti;
5185         char *capaName, *str, *valStr;
5186         guint32 offset = 0;
5187         guint32 len = 0;
5188         guint32 capaStart = 0;          /* Start offset of the capability */
5189         guint32 capaLen = 0;            /* Length of the entire capability */
5190         guint32 capaValueLen = 0;       /* Length of the capability value & type */
5191         guint32 tvb_len = tvb_reported_length(tvb);
5192         gboolean ok = FALSE;
5193         guint8 peek;
5194         guint32 value;
5195
5196         if (tvb_len == 0) {
5197                 DebugLog(("add_capabilities(): Capabilities = 0\n"));
5198                 return;
5199         }
5200
5201         DebugLog(("add_capabilities(): capabilities to process\n"));
5202
5203         ti = proto_tree_add_item(tree, hf_capabilities_section,
5204                         tvb, 0, tvb_len, bo_little_endian);
5205         wsp_capabilities = proto_item_add_subtree(ti, ett_capabilities);
5206
5207         while (offset < tvb_len) {
5208                 /*
5209                  * WSP capabilities consist of:
5210                  *  - a guint32 length field,
5211                  *  - a capability identifier as Token-text or Short-integer,
5212                  *  - a capability-specific sequence of <length> octets.
5213                  */
5214                 capaStart = offset;
5215                 /*
5216                  * Now Offset points to the 1st byte of a capability field.
5217                  * Get the length of the capability field
5218                  */
5219                 capaValueLen = tvb_get_guintvar(tvb, offset, &len);
5220                 capaLen = capaValueLen + len;
5221                 offset += len;
5222                 /*
5223                  * Now offset points to the 1st byte of the capability type.
5224                  * Get the capability identifier.
5225                  */
5226                 peek = tvb_get_guint8(tvb, offset);
5227                 if (is_token_text(peek)) { /* Literal capability name */
5228                         /* 1. Get the string from the tvb */
5229                         get_token_text(capaName, tvb, offset, len, ok);
5230                         if (! ok) {
5231                                 DebugLog(("add_capabilities(): expecting capability name as token_text "
5232                                                         "at offset %u (1st char = 0x%02x)\n", offset, peek));
5233                                 return;
5234                         }
5235                         /* 2. Look up the string capability name */
5236                         if (strcasecmp(capaName, "client-sdu-size") == 0) {
5237                                 peek = WSP_CAPA_CLIENT_SDU_SIZE;
5238                         } else if (strcasecmp(capaName, "server-sdu-size") == 0) {
5239                                 peek = WSP_CAPA_SERVER_SDU_SIZE;
5240                         } else if (strcasecmp(capaName, "protocol options") == 0) {
5241                                 peek = WSP_CAPA_PROTOCOL_OPTIONS;
5242                         } else if (strcasecmp(capaName, "method-mor") == 0) {
5243                                 peek = WSP_CAPA_METHOD_MOR;
5244                         } else if (strcasecmp(capaName, "push-mor") == 0) {
5245                                 peek = WSP_CAPA_PUSH_MOR;
5246                         } else if (strcasecmp(capaName, "extended methods") == 0) {
5247                                 peek = WSP_CAPA_EXTENDED_METHODS;
5248                         } else if (strcasecmp(capaName, "header code pages") == 0) {
5249                                 peek = WSP_CAPA_HEADER_CODE_PAGES;
5250                         } else if (strcasecmp(capaName, "aliases") == 0) {
5251                                 peek = WSP_CAPA_ALIASES;
5252                         } else if (strcasecmp(capaName, "client-message-size") == 0) {
5253                                 peek = WSP_CAPA_CLIENT_MESSAGE_SIZE;
5254                         } else if (strcasecmp(capaName, "server-message-size") == 0) {
5255                                 peek = WSP_CAPA_SERVER_MESSAGE_SIZE;
5256                         } else {
5257                                 DebugLog(("add_capabilities(): unknown capability '%s' at offset %u\n",
5258                                                         capaName, offset));
5259                                 proto_tree_add_text(wsp_capabilities, tvb, capaStart, capaLen,
5260                                                 "Unknown or invalid textual capability: %s", capaName);
5261                                 g_free(capaName);
5262                                 /* Skip this capability */
5263                                 offset = capaStart + capaLen;
5264                                 continue;
5265                         }
5266                         g_free(capaName);
5267                         offset += len;
5268                         /* Now offset points to the 1st value byte of the capability. */
5269                 } else if (peek < 0x80) {
5270                         DebugLog(("add_capabilities(): invalid capability type identifier 0x%02X at offset %u.",
5271                                                 peek, offset - 1));
5272                         proto_tree_add_text(wsp_capabilities, tvb, capaStart, capaLen,
5273                                         "Invalid well-known capability: 0x%02X", peek);
5274                         /* Skip further capability parsing */
5275                         return;
5276                 }
5277                 if (peek & 0x80) { /* Well-known capability */
5278                         peek &= 0x7F;
5279                         len = 1;
5280                         offset++;
5281                         /* Now offset points to the 1st value byte of the capability. */
5282                 }
5283                 /* Now the capability type is known */
5284                 switch (peek) {
5285                         case WSP_CAPA_CLIENT_SDU_SIZE:
5286                                 value = tvb_get_guintvar(tvb, offset, &len);
5287                                 DebugLog(("add_capabilities(client-sdu-size): "
5288                                                         "guintvar = %u (0x%X) at offset %u (1st byte = 0x%02X) (len = %u)\n",
5289                                                         value, value, offset, tvb_get_guint8(tvb, offset), len));
5290                                 proto_tree_add_uint(wsp_capabilities, hf_capa_client_sdu_size,
5291                                                 tvb, capaStart, capaLen, value);
5292                                 break;
5293                         case WSP_CAPA_SERVER_SDU_SIZE:
5294                                 value = tvb_get_guintvar(tvb, offset, &len);
5295                                 DebugLog(("add_capabilities(server-sdu-size): "
5296                                                         "guintvar = %u (0x%X) at offset %u (1st byte = 0x%02X) (len = %u)\n",
5297                                                         value, value, offset, tvb_get_guint8(tvb, offset), len));
5298                                 proto_tree_add_uint(wsp_capabilities, hf_capa_server_sdu_size,
5299                                                 tvb, capaStart, capaLen, value);
5300                                 break;
5301                         case WSP_CAPA_PROTOCOL_OPTIONS:
5302                                 ti = proto_tree_add_string(wsp_capabilities, hf_capa_protocol_options,
5303                                                 tvb, capaStart, capaLen, "");
5304                                 capa_subtree = proto_item_add_subtree(ti, ett_capability);
5305                                 /*
5306                                  * The bits are stored in one or more octets, not an
5307                                  * uintvar-integer! Note that capability name and value
5308                                  * have length capaValueLength, and that the capability
5309                                  * name has length = len. Hence the remaining length is
5310                                  * given by capaValueLen - len.
5311                                  */
5312                                 switch (capaValueLen - len) {
5313                                         case 1:
5314                                                 value = tvb_get_guint8(tvb, offset);
5315                                                 len = 1;
5316                                                 break;
5317                                         default:
5318                                                 /*
5319                                                  * The WSP spec foresees that this bit field can be
5320                                                  * extended in the future. This does not make sense yet.
5321                                                  */
5322                                                         DebugLog(("add_capabilities(protocol options): "
5323                                                                                 "bit field too large (%u bytes)\n",
5324                                                                                 capaValueLen));
5325                                                         proto_item_append_text(ti,
5326                                                                         " <warning: bit field too large>");
5327                                                         offset = capaStart + capaLen;
5328                                                         continue;
5329                                 }
5330                                 DebugLog(("add_capabilities(protocol options): "
5331                                                         "guintvar = %u (0x%X) at offset %u (1st byte = 0x%02X) (len = %u)\n",
5332                                                         value, value, offset, tvb_get_guint8(tvb, offset), len));
5333                                 if (value & 0x80)
5334                                         proto_item_append_string(ti, " (confirmed push facility)");
5335                                 if (value & 0x40)
5336                                         proto_item_append_string(ti, " (push facility)");
5337                                 if (value & 0x20)
5338                                         proto_item_append_string(ti, " (session resume facility)");
5339                                 if (value & 0x10)
5340                                         proto_item_append_string(ti, " (acknowledgement headers)");
5341                                 if (value & 0x08)
5342                                         proto_item_append_string(ti, " (large data transfer)");
5343                                 if (value & 0xFFFFFF07)
5344                                         proto_item_append_text(ti, " <warning: reserved bits have been set>");
5345                                 proto_tree_add_boolean(capa_subtree,
5346                                                 hf_capa_protocol_option_confirmed_push,
5347                                                 tvb, offset, len, value);
5348                                 proto_tree_add_boolean(capa_subtree,
5349                                                 hf_capa_protocol_option_push,
5350                                                 tvb, offset, len, value);
5351                                 proto_tree_add_boolean(capa_subtree,
5352                                                 hf_capa_protocol_option_session_resume,
5353                                                 tvb, offset, len, value);
5354                                 proto_tree_add_boolean(capa_subtree,
5355                                                 hf_capa_protocol_option_ack_headers,
5356                                                 tvb, offset, len, value);
5357                                 proto_tree_add_boolean(capa_subtree,
5358                                                 hf_capa_protocol_option_large_data_transfer,
5359                                                 tvb, offset, len, value);
5360                                 break;
5361                         case WSP_CAPA_METHOD_MOR:
5362                                 value = tvb_get_guint8(tvb, offset);
5363                                 proto_tree_add_uint (wsp_capabilities,
5364                                                 hf_capa_method_mor,
5365                                                 tvb, capaStart, capaLen, value);
5366                                 break;
5367                         case WSP_CAPA_PUSH_MOR:
5368                                 value = tvb_get_guint8(tvb, offset);
5369                                 proto_tree_add_uint (wsp_capabilities,
5370                                                 hf_capa_push_mor,
5371                                                 tvb, capaStart, capaLen, value);
5372                                 break;
5373                         case WSP_CAPA_EXTENDED_METHODS:
5374                                 /* Extended Methods capability format:
5375                                  * Connect PDU: collection of { Method (octet), Method-name (Token-text) }
5376                                  * ConnectReply PDU: collection of accepted { Method (octet) }
5377                                  */
5378                                 ti = proto_tree_add_string(wsp_capabilities,
5379                                                 hf_capa_extended_methods,
5380                                                 tvb, capaStart, capaLen, "");
5381                                 if (pdu_type == WSP_PDU_CONNECT) {
5382                                         while (offset < capaStart + capaLen) {
5383                                                 peek = tvb_get_guint8(tvb, offset++);
5384                                                 get_text_string(str, tvb, offset, len, ok);
5385                                                 if (! ok) {
5386                                                         proto_item_append_text(ti, " <error: invalid capability encoding>");
5387                                                         DebugLog(("add_capability(extended methods): "
5388                                                                                 "invalid method name at offset %u "
5389                                                                                 "(octet = 0x%02X)\n",
5390                                                                                 offset, tvb_get_guint8(tvb, offset)));
5391                                                         return;
5392                                                 }
5393                                                 valStr = g_strdup_printf(" (0x%02x = %s)", peek, str);
5394                                                 DebugLog(("add_capabilities(extended methods):%s\n",
5395                                                                         valStr));
5396                                                 proto_item_append_string(ti, valStr);
5397                                                 g_free(valStr);
5398                                                 g_free(str);
5399                                                 offset += len;
5400                                         }
5401                                 } else {
5402                                         while (offset < capaStart + capaLen) {
5403                                                 peek = tvb_get_guint8(tvb, offset++);
5404                                                 valStr = g_strdup_printf(" (0x%02x)", peek);
5405                                                 DebugLog(("add_capabilities(extended methods):%s\n",
5406                                                                         valStr));
5407                                                 proto_item_append_string(ti, valStr);
5408                                                 g_free(valStr);
5409                                         }
5410                                 }
5411                                 break;
5412                         case WSP_CAPA_HEADER_CODE_PAGES:
5413                                 /* Header Code Pages capability format:
5414                                  * Connect PDU: collection of { Page-id (octet), Page-name (Token-text) }
5415                                  * ConnectReply PDU: collection of accepted { Page-id (octet) }
5416                                  */
5417                                 ti = proto_tree_add_string(wsp_capabilities,
5418                                                 hf_capa_header_code_pages,
5419                                                 tvb, capaStart, capaLen, "");
5420                                 if (pdu_type == WSP_PDU_CONNECT) {
5421                                         while (offset < capaStart + capaLen) {
5422                                                 peek = tvb_get_guint8(tvb, offset++);
5423                                                 get_text_string(str, tvb, offset, len, ok);
5424                                                 if (! ok) {
5425                                                         proto_item_append_text(ti,
5426                                                                         " <error: invalid capability encoding>");
5427                                                         DebugLog(("add_capability(header code pages): "
5428                                                                                 "invalid header code page name at offset %u "
5429                                                                                 "(octet = 0x%02X)\n",
5430                                                                                 offset, tvb_get_guint8(tvb, offset)));
5431                                                         return;
5432                                                 }
5433                                                 valStr = g_strdup_printf(" (0x%02x = %s)", peek, str);
5434                                                 DebugLog(("add_capabilities(header code pages):%s\n",
5435                                                                         valStr));
5436                                                 proto_item_append_string(ti, valStr);
5437                                                 g_free(valStr);
5438                                                 g_free(str);
5439                                                 offset += len;
5440                                         }
5441                                 } else {
5442                                         while (offset < capaStart + capaLen) {
5443                                                 peek = tvb_get_guint8(tvb, offset++);
5444                                                 valStr = g_strdup_printf(" (0x%02x)", peek);
5445                                                 DebugLog(("add_capabilities(header code pages):%s\n",
5446                                                                         valStr));
5447                                                 proto_item_append_string(ti, valStr);
5448                                                 g_free(valStr);
5449                                         }
5450                                 }
5451                                 break;
5452                         case WSP_CAPA_ALIASES:
5453                                 /* TODO - same format as redirect addresses */
5454                                 proto_tree_add_item(wsp_capabilities, hf_capa_aliases,
5455                                                 tvb, capaStart, capaLen, bo_little_endian);
5456                                 break;
5457                         case WSP_CAPA_CLIENT_MESSAGE_SIZE:
5458                                 value = tvb_get_guintvar(tvb, offset, &len);
5459                                 DebugLog(("add_capabilities(client-message-size): "
5460                                                         "guintvar = %u (0x%X) at offset %u (1st byte = 0x%02X) (len = %u)\n",
5461                                                         value, value, offset, tvb_get_guint8(tvb, offset), len));
5462                                 proto_tree_add_uint(wsp_capabilities, hf_capa_client_message_size,
5463                                                 tvb, capaStart, capaLen, value);
5464                                 break;
5465                         case WSP_CAPA_SERVER_MESSAGE_SIZE:
5466                                 value = tvb_get_guintvar(tvb, offset, &len);
5467                                 DebugLog(("add_capabilities(server-message-size): "
5468                                                         "guintvar = %u (0x%X) at offset %u (1st byte = 0x%02X) (len = %u)\n",
5469                                                         value, value, offset, tvb_get_guint8(tvb, offset), len));
5470                                 proto_tree_add_uint(wsp_capabilities, hf_capa_server_message_size,
5471                                                 tvb, capaStart, capaLen, value);
5472                                 break;
5473                         default:
5474                                 proto_tree_add_text(wsp_capabilities, tvb, capaStart, capaLen,
5475                                                 "Unknown well-known capability: 0x%02X", peek);
5476                                 break;
5477                 }
5478                 offset = capaStart + capaLen;
5479         }
5480 }
5481
5482 void
5483 add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType,
5484     const char *contentTypeStr)
5485 {
5486         guint offset = 0;
5487         guint variableStart = 0;
5488         guint variableEnd = 0;
5489         guint valueStart = 0;
5490         guint valueEnd = 0;
5491         guint8 peek = 0;
5492         proto_item *ti;
5493         proto_tree *sub_tree;
5494
5495         DebugLog(("add_post_data() - START\n"));
5496
5497         /* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,-1,bo_little_endian); */
5498         ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,-1,bo_little_endian);
5499         sub_tree = proto_item_add_subtree(ti, ett_post);
5500
5501         if ( (contentTypeStr == NULL && contentType == 0x12) 
5502                         || (contentTypeStr && (strcasecmp(contentTypeStr,
5503                                                 "application/x-www-form-urlencoded") == 0)) )
5504         {
5505                 /*
5506                  * URL Encoded data.
5507                  * Iterate through post data.
5508                  */
5509                 for (offset = 0; offset < tvb_reported_length (tvb); offset++)
5510                 {
5511                         peek = tvb_get_guint8 (tvb, offset);
5512                         if (peek == '=')
5513                         {
5514                                 variableEnd = offset;
5515                                 valueStart = offset+1;
5516                         }
5517                         else if (peek == '&')
5518                         {
5519                                 if (variableEnd > 0)
5520                                 {
5521                                         add_post_variable (sub_tree, tvb, variableStart, variableEnd, valueStart, offset);
5522                                 }
5523                                 variableStart = offset+1;
5524                                 variableEnd = 0;
5525                                 valueStart = 0;
5526                                 valueEnd = 0;
5527                         }
5528                 }
5529
5530                 /* See if there's outstanding data */
5531                 if (variableEnd > 0)
5532                 {
5533                         add_post_variable (sub_tree, tvb, variableStart, variableEnd, valueStart, offset);
5534                 }
5535         }
5536         else if ((contentType == 0x22) || (contentType == 0x23) || (contentType == 0x24) ||
5537                  (contentType == 0x25) || (contentType == 0x26) || (contentType == 0x33))
5538         {
5539                 add_multipart_data(sub_tree, tvb);
5540         }
5541         DebugLog(("add_post_data() - END\n"));
5542 }
5543
5544 static void
5545 add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
5546 {
5547         int variableLength = variableEnd-variableStart;
5548         int valueLength = 0;
5549         char *variableBuffer;
5550         char *valueBuffer;
5551
5552         variableBuffer = g_malloc (variableLength+1);
5553         strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength);
5554         variableBuffer[variableLength] = 0;
5555
5556         if (valueEnd < valueStart)
5557         {
5558                 valueBuffer = g_malloc (1);
5559                 valueBuffer[0] = 0;
5560                 valueEnd = valueStart;
5561         }
5562         else
5563         {
5564                 valueLength = valueEnd-valueStart;
5565                 valueBuffer = g_malloc (valueLength+1);
5566                 strncpy (valueBuffer, tvb_get_ptr (tvb, valueStart, valueLength), valueLength);
5567                 valueBuffer[valueLength] = 0;
5568         }
5569
5570         /* Check for variables with no value */
5571         if (valueStart >= tvb_reported_length (tvb))
5572         {
5573                 valueStart = tvb_reported_length (tvb);
5574                 valueEnd = valueStart;
5575         }
5576         valueLength = valueEnd-valueStart;
5577
5578         proto_tree_add_text (tree, tvb, variableStart, valueEnd-variableStart, "%s: %s", variableBuffer, valueBuffer);
5579
5580         g_free (variableBuffer);
5581         g_free (valueBuffer);
5582 }
5583
5584 static void
5585 add_multipart_data (proto_tree *tree, tvbuff_t *tvb)
5586 {
5587         int              offset = 0;
5588         guint            nextOffset;
5589         guint            nEntries = 0;
5590         guint            count;
5591         guint            HeadersLen;
5592         guint            DataLen;
5593         guint            contentType = 0;
5594         const char      *contentTypeStr;
5595         tvbuff_t        *tmp_tvb;
5596         int              partnr = 1;
5597         int              part_start;
5598
5599         proto_item      *sub_tree = NULL,
5600                         *ti;
5601         proto_tree      *mpart_tree;
5602
5603         DebugLog(("add_multipart_data(): offset = %u, byte = 0x%02x: ",
5604                                 offset, tvb_get_guint8(tvb,offset)));
5605         nEntries = tvb_get_guintvar (tvb, offset, &count);
5606         DebugLog(("parts = %u\n", nEntries));
5607         offset += count;
5608         if (nEntries)
5609         {
5610                 sub_tree = proto_tree_add_text(tree, tvb, offset - count, 0,
5611                                         "Multipart body");
5612                 proto_item_add_subtree(sub_tree, ett_mpartlist);
5613         }
5614         while (nEntries--)
5615         {
5616                 DebugLog(("add_multipart_data(): Parts to do after this: %u"
5617                                 " (offset = %u, 0x%02x): ",
5618                                 nEntries, offset, tvb_get_guint8(tvb,offset)));
5619                 part_start = offset;
5620                 HeadersLen = tvb_get_guintvar (tvb, offset, &count);
5621                 offset += count;
5622                 DataLen = tvb_get_guintvar (tvb, offset, &count);
5623                 offset += count;
5624                 ti = proto_tree_add_uint(sub_tree, hf_wsp_mpart, tvb, part_start,
5625                                         HeadersLen + DataLen + (offset - part_start), partnr);
5626                 mpart_tree = proto_item_add_subtree(ti, ett_multiparts);
5627                 nextOffset = add_content_type (mpart_tree, tvb, offset, &contentType, &contentTypeStr);
5628                 HeadersLen -= (nextOffset - offset);
5629                 if (HeadersLen > 0)
5630                 {
5631                         tmp_tvb = tvb_new_subset (tvb, nextOffset, HeadersLen, HeadersLen);
5632                         add_headers (mpart_tree, tmp_tvb, hf_wsp_headers_section);
5633                 }
5634                 offset = nextOffset + HeadersLen;
5635                 /* TODO - Try the dissectors of the multipart content */
5636                 proto_tree_add_item (mpart_tree, hf_wsp_multipart_data, tvb, offset, DataLen, bo_little_endian);
5637                 offset += DataLen;
5638                 partnr++;
5639         }
5640 }
5641
5642
5643 /* Register the protocol with Ethereal */
5644 void
5645 proto_register_wsp(void)
5646 {
5647
5648 /* Setup list of header fields */
5649         static hf_register_info hf[] = {
5650                 { &hf_wsp_header_tid,
5651                         {       "Transaction ID",
5652                                 "wsp.TID",
5653                                  FT_UINT8, BASE_HEX, NULL, 0x00,
5654                                 "WSP Transaction ID (for connectionless WSP)", HFILL
5655                         }
5656                 },
5657                 { &hf_wsp_header_pdu_type,
5658                         {       "PDU Type",
5659                                 "wsp.pdu_type",
5660                                  FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
5661                                 "PDU Type", HFILL
5662                         }
5663                 },
5664                 { &hf_wsp_version_major,
5665                         {       "Version (Major)",
5666                                 "wsp.version.major",
5667                                  FT_UINT8, BASE_DEC, NULL, 0xF0,
5668                                 "Version (Major)", HFILL
5669                         }
5670                 },
5671                 { &hf_wsp_version_minor,
5672                         {       "Version (Minor)",
5673                                 "wsp.version.minor",
5674                                  FT_UINT8, BASE_DEC, NULL, 0x0F,
5675                                 "Version (Minor)", HFILL
5676                         }
5677                 },
5678                 { &hf_capabilities_length,
5679                         {       "Capabilities Length",
5680                                 "wsp.capabilities.length",
5681                                  FT_UINT32, BASE_DEC, NULL, 0x00,
5682                                 "Length of Capabilities field (bytes)", HFILL
5683                         }
5684                 },
5685                 { &hf_wsp_header_length,
5686                         {       "Headers Length",
5687                                 "wsp.headers_length",
5688                                  FT_UINT32, BASE_DEC, NULL, 0x00,
5689                                 "Length of Headers field (bytes)", HFILL
5690                         }
5691                 },
5692                 { &hf_capabilities_section,
5693                         {       "Capabilities",
5694                                 "wsp.capabilities",
5695                                  FT_NONE, BASE_DEC, NULL, 0x00,
5696                                 "Capabilities", HFILL
5697                         }
5698                 },
5699                 { &hf_wsp_headers_section,
5700                         {       "Headers",
5701                                 "wsp.headers",
5702                                  FT_NONE, BASE_DEC, NULL, 0x00,
5703                                 "Headers", HFILL
5704                         }
5705                 },
5706                 { &hf_wsp_header_uri_len,
5707                         {       "URI Length",
5708                                 "wsp.uri_length",
5709                                  FT_UINT32, BASE_DEC, NULL, 0x00,
5710                                 "Length of URI field", HFILL
5711                         }
5712                 },
5713                 { &hf_wsp_header_uri,
5714                         {       "URI",
5715                                 "wsp.uri",
5716                                  FT_STRING, BASE_NONE, NULL, 0x00,
5717                                 "URI", HFILL
5718                         }
5719                 },
5720                 { &hf_wsp_server_session_id,
5721                         {       "Server Session ID",
5722                                 "wsp.server.session_id",
5723                                  FT_UINT32, BASE_DEC, NULL, 0x00,
5724                                 "Server Session ID", HFILL
5725                         }
5726                 },
5727                 { &hf_wsp_header_status,
5728                         {       "Status",
5729                                 "wsp.reply.status",
5730                                  FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
5731                                 "Reply Status", HFILL
5732                         }
5733                 },
5734                 { &hf_wsp_parameter_type,
5735                         {       "Type",
5736                                 "wsp.parameter.type",
5737                                  FT_UINT32, BASE_DEC, NULL, 0x00,
5738                                 "Type", HFILL
5739                         }
5740                 },
5741                 { &hf_wsp_parameter_name,
5742                         {       "Name",
5743                                 "wsp.parameter.name",
5744                                  FT_STRING, BASE_NONE, NULL, 0x00,
5745                                 "Name", HFILL
5746                         }
5747                 },
5748                 { &hf_wsp_parameter_filename,
5749                         {       "Filename",
5750                                 "wsp.parameter.filename",
5751                                  FT_STRING, BASE_NONE, NULL, 0x00,
5752                                 "Filename", HFILL
5753                         }
5754                 },
5755                 { &hf_wsp_parameter_start,
5756                         {       "Start",
5757                                 "wsp.parameter.start",
5758                                  FT_STRING, BASE_NONE, NULL, 0x00,
5759                                 "Start", HFILL
5760                         }
5761                 },
5762                 { &hf_wsp_parameter_start_info,
5763                         {       "Start-info",
5764                                 "wsp.parameter.start_info",
5765                                  FT_STRING, BASE_NONE, NULL, 0x00,
5766                                 "Start-info", HFILL
5767                         }
5768                 },
5769                 { &hf_wsp_parameter_comment,
5770                         {       "Comment",
5771                                 "wsp.parameter.comment",
5772                                  FT_STRING, BASE_NONE, NULL, 0x00,
5773                                 "Comment", HFILL
5774                         }
5775                 },
5776                 { &hf_wsp_parameter_domain,
5777                         {       "Domain",
5778                                 "wsp.parameter.domain",
5779                                  FT_STRING, BASE_NONE, NULL, 0x00,
5780                                 "Domain", HFILL
5781                         }
5782                 },
5783                 { &hf_wsp_parameter_path,
5784                         {       "Path",
5785                                 "wsp.parameter.path",
5786                                  FT_STRING, BASE_NONE, NULL, 0x00,
5787                                 "Path", HFILL
5788                         }
5789                 },
5790                 { &hf_wsp_parameter_sec,
5791                         {       "SEC",
5792                                 "wsp.parameter.sec",
5793                                  FT_UINT8, BASE_HEX, VALS (vals_wsp_parameter_sec), 0x00,
5794                                 "SEC parameter (Content-Type: application/vnd.wap.connectivity-wbxml)", HFILL
5795                         }
5796                 },
5797                 { &hf_wsp_parameter_mac,
5798                         {       "MAC",
5799                                 "wsp.parameter.mac",
5800                                  FT_STRING, BASE_NONE, NULL, 0x00,
5801                                 "MAC parameter (Content-Type: application/vnd.wap.connectivity-wbxml)", HFILL
5802                         }
5803                 },
5804                 { &hf_wsp_parameter_upart_type,
5805                         {       "Type",
5806                                 "wsp.parameter.upart.type",
5807                                  FT_STRING, BASE_NONE, NULL, 0x00,
5808                                 "Multipart type", HFILL
5809                         }
5810                 },
5811                 { &hf_wsp_parameter_level,
5812                         {       "Level",
5813                                 "wsp.parameter.level",
5814                                  FT_STRING, BASE_NONE, NULL, 0x00,
5815                                 "Level parameter", HFILL
5816                         }
5817                 },
5818                 { &hf_wsp_reply_data,
5819                         {       "Data",
5820                                 "wsp.reply.data",
5821                                  FT_NONE, BASE_NONE, NULL, 0x00,
5822                                 "Data", HFILL
5823                         }
5824                 },
5825                 { &hf_wsp_header_shift_code,
5826                         {       "Switching to WSP header code-page",
5827                                 "wsp.code_page",
5828                                  FT_UINT8, BASE_DEC, NULL, 0x00,
5829                                 "Header code-page shift code", HFILL
5830                         }
5831                 },
5832                 /*
5833                  * CO-WSP capability negotiation
5834                  */
5835                 { &hf_capa_client_sdu_size,
5836                         {       "Client SDU Size",
5837                                 "wsp.capability.client_sdu_size",
5838                                  FT_UINT8, BASE_DEC, NULL, 0x00,
5839                                 "Client Service Data Unit size (bytes)", HFILL
5840                         }
5841                 },
5842                 { &hf_capa_server_sdu_size,
5843                         {       "Server SDU Size",
5844                                 "wsp.capability.server_sdu_size",
5845                                  FT_UINT8, BASE_DEC, NULL, 0x00,
5846                                 "Server Service Data Unit size (bytes)", HFILL
5847                         }
5848                 },
5849                 { &hf_capa_protocol_options,
5850                         {       "Protocol Options",
5851                                 "wsp.capability.protocol_opt",
5852                                  FT_STRING, BASE_HEX, NULL, 0x00,
5853                                 "Protocol Options", HFILL
5854                         }
5855                 },
5856                 { &hf_capa_protocol_option_confirmed_push,
5857                         {       "Confirmed Push facility",
5858                                 "wsp.capability.protocol_option.confirmed_push",
5859                                 FT_BOOLEAN, 8, NULL, 0x80,
5860                                 "If set, this CO-WSP session supports the Confirmed Push facility", HFILL
5861                         }
5862                 },
5863                 { &hf_capa_protocol_option_push,
5864                         {       "Push facility",
5865                                 "wsp.capability.protocol_option.push",
5866                                 FT_BOOLEAN, 8, NULL, 0x40,
5867                                 "If set, this CO-WSP session supports the Push facility", HFILL
5868                         }
5869                 },
5870                 { &hf_capa_protocol_option_session_resume,
5871                         {       "Session Resume facility",
5872                                 "wsp.capability.protocol_option.session_resume",
5873                                 FT_BOOLEAN, 8, NULL, 0x20,
5874                                 "If set, this CO-WSP session supports the Session Resume facility", HFILL
5875                         }
5876                 },
5877                 { &hf_capa_protocol_option_ack_headers,
5878                         {       "Acknowledgement headers",
5879                                 "wsp.capability.protocol_option.ack_headers",
5880                                 FT_BOOLEAN, 8, NULL, 0x10,
5881                                 "If set, this CO-WSP session supports Acknowledgement headers", HFILL
5882                         }
5883                 },
5884                 { &hf_capa_protocol_option_large_data_transfer,
5885                         {       "Large data transfer",
5886                                 "wsp.capability.protocol_option.large_data_transfer",
5887                                 FT_BOOLEAN, 8, NULL, 0x08,
5888                                 "If set, this CO-WSP session supports Large data transfer", HFILL
5889                         }
5890                 },
5891                 { &hf_capa_method_mor,
5892                         {       "Method MOR",
5893                                 "wsp.capability.method_mor",
5894                                  FT_UINT8, BASE_DEC, NULL, 0x00,
5895                                 "Method MOR", HFILL
5896                         }
5897                 },
5898                 { &hf_capa_push_mor,
5899                         {       "Push MOR",
5900                                 "wsp.capability.push_mor",
5901                                  FT_UINT8, BASE_DEC, NULL, 0x00,
5902                                 "Push MOR", HFILL
5903                         }
5904                 },
5905                 { &hf_capa_extended_methods,
5906                         {       "Extended Methods",
5907                                 "wsp.capability.extended_methods",
5908                                  FT_STRING, BASE_HEX, NULL, 0x00,
5909                                 "Extended Methods", HFILL
5910                         }
5911                 },
5912                 { &hf_capa_header_code_pages,
5913                         {       "Header Code Pages",
5914                                 "wsp.capability.code_pages",
5915                                  FT_STRING, BASE_HEX, NULL, 0x00,
5916                                 "Header Code Pages", HFILL
5917                         }
5918                 },
5919                 { &hf_capa_aliases,
5920                         {       "Aliases",
5921                                 "wsp.capability.aliases",
5922                                  FT_BYTES, BASE_NONE, NULL, 0x00,
5923                                 "Aliases", HFILL
5924                         }
5925                 },
5926                 { &hf_capa_client_message_size,
5927                         {       "Client Message Size",
5928                                 "wsp.capability.client_message_size",
5929                                  FT_UINT8, BASE_DEC, NULL, 0x00,
5930                                 "Client Message size (bytes)", HFILL
5931                         }
5932                 },
5933                 { &hf_capa_server_message_size,
5934                         {       "Server Message Size",
5935                                 "wsp.capability.server_message_size",
5936                                  FT_UINT8, BASE_DEC, NULL, 0x00,
5937                                 "Server Message size (bytes)", HFILL
5938                         }
5939                 },
5940                 { &hf_wsp_post_data,
5941                         {       "Data (Post)",
5942                                 "wsp.post.data",
5943                                  FT_NONE, BASE_NONE, NULL, 0x00,
5944                                 "Post Data", HFILL
5945                         }
5946                 },
5947                 { &hf_wsp_push_data,
5948                         {       "Push Data",
5949                                 "wsp.push.data",
5950                                  FT_NONE, BASE_NONE, NULL, 0x00,
5951                                 "Push Data", HFILL
5952                         }
5953                 },
5954                 { &hf_wsp_multipart_data,
5955                         {       "Data in this part",
5956                                 "wsp.multipart.data",
5957                                  FT_NONE, BASE_NONE, NULL, 0x00,
5958                                 "The data of 1 MIME-multipart part.", HFILL
5959                         }
5960                 },
5961                 { &hf_wsp_mpart,
5962                         {       "Part",
5963                                 "wsp.multipart",
5964                                  FT_UINT32, BASE_DEC, NULL, 0x00,
5965                                 "MIME part of multipart data.", HFILL
5966                         }
5967                 },
5968                 { &hf_wsp_redirect_flags,
5969                         {       "Flags",
5970                                 "wsp.redirect.flags",
5971                                  FT_UINT8, BASE_HEX, NULL, 0x00,
5972                                 "Redirect Flags", HFILL
5973                         }
5974                 },
5975                 { &hf_wsp_redirect_permanent,
5976                         {       "Permanent Redirect",
5977                                 "wsp.redirect.flags.permanent",
5978                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), PERMANENT_REDIRECT,
5979                                 "Permanent Redirect", HFILL
5980                         }
5981                 },
5982                 { &hf_wsp_redirect_reuse_security_session,
5983                         {       "Reuse Security Session",
5984                                 "wsp.redirect.flags.reuse_security_session",
5985                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), REUSE_SECURITY_SESSION,
5986                                 "If set, the existing Security Session may be reused", HFILL
5987                         }
5988                 },
5989                 { &hf_redirect_addresses,
5990                         {       "Redirect Addresses",
5991                                 "wsp.redirect.addresses",
5992                                 FT_NONE, BASE_NONE, NULL, 0x00,
5993                                 "List of Redirect Addresses", HFILL
5994                         }
5995                 },
5996
5997                 /*
5998                  * Addresses
5999                  */
6000                 { &hf_address_entry,
6001                         {       "Address Record",
6002                                 "wsp.address",
6003                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6004                                 "Address Record", HFILL
6005                         }
6006                 },
6007                 { &hf_address_flags_length,
6008                         {       "Flags/Length",
6009                                 "wsp.address.flags",
6010                                  FT_UINT8, BASE_HEX, NULL, 0x00,
6011                                 "Address Flags/Length", HFILL
6012                         }
6013                 },
6014                 { &hf_address_flags_length_bearer_type_included,
6015                         {       "Bearer Type Included",
6016                                 "wsp.address.flags.bearer_type_included",
6017                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), BEARER_TYPE_INCLUDED,
6018                                 "Address bearer type included", HFILL
6019                         }
6020                 },
6021                 { &hf_address_flags_length_port_number_included,
6022                         {       "Port Number Included",
6023                                 "wsp.address.flags.port_number_included",
6024                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), PORT_NUMBER_INCLUDED,
6025                                 "Address port number included", HFILL
6026                         }
6027                 },
6028                 { &hf_address_flags_length_address_len,
6029                         {       "Address Length",
6030                                 "wsp.address.flags.length",
6031                                  FT_UINT8, BASE_DEC, NULL, ADDRESS_LEN,
6032                                 "Address Length", HFILL
6033                         }
6034                 },
6035                 { &hf_address_bearer_type,
6036                         {       "Bearer Type",
6037                                 "wsp.address.bearer_type",
6038                                  FT_UINT8, BASE_HEX, VALS(vals_bearer_types), 0x0,
6039                                 "Bearer Type", HFILL
6040                         }
6041                 },
6042                 { &hf_address_port_num,
6043                         {       "Port Number",
6044                                 "wsp.address.port",
6045                                  FT_UINT16, BASE_DEC, NULL, 0x0,
6046                                 "Port Number", HFILL
6047                         }
6048                 },
6049                 { &hf_address_ipv4_addr,
6050                         {       "IPv4 Address",
6051                                 "wsp.address.ipv4",
6052                                  FT_IPv4, BASE_NONE, NULL, 0x0,
6053                                 "Address (IPv4)", HFILL
6054                         }
6055                 },
6056                 { &hf_address_ipv6_addr,
6057                         {       "IPv6 Address",
6058                                 "wsp.address.ipv6",
6059                                  FT_IPv6, BASE_NONE, NULL, 0x0,
6060                                 "Address (IPv6)", HFILL
6061                         }
6062                 },
6063                 { &hf_address_addr,
6064                         {       "Address",
6065                                 "wsp.address.unknown",
6066                                  FT_BYTES, BASE_NONE, NULL, 0x0,
6067                                 "Address (unknown)", HFILL
6068                         }
6069                 },
6070
6071
6072                 /*
6073                  * New WSP header fields
6074                  */
6075
6076
6077                 /* WSP header name */
6078                 { &hf_hdr_name,
6079                         {       "Header name",
6080                                 "wsp.header.name",
6081                                 FT_STRING, BASE_NONE, NULL, 0x00,
6082                                 "Name of the WSP header", HFILL
6083                         }
6084                 },
6085                 /* WSP headers start here */
6086                 { &hf_hdr_accept,
6087                         {       "Accept",
6088                                 "wsp.header.accept",
6089                                 FT_STRING, BASE_NONE, NULL, 0x00,
6090                                 "WSP header Accept", HFILL
6091                         }
6092                 },
6093                 { &hf_hdr_accept_charset,
6094                         {       "Accept-Charset",
6095                                 "wsp.header.accept_charset",
6096                                 FT_STRING, BASE_NONE, NULL, 0x00,
6097                                 "WSP header Accept-Charset", HFILL
6098                         }
6099                 },
6100                 { &hf_hdr_accept_encoding,
6101                         {       "Accept-Encoding",
6102                                 "wsp.header.accept_encoding",
6103                                 FT_STRING, BASE_NONE, NULL, 0x00,
6104                                 "WSP header Accept-Encoding", HFILL
6105                         }
6106                 },
6107                 { &hf_hdr_accept_language,
6108                         {       "Accept-Language",
6109                                 "wsp.header.accept_language",
6110                                 FT_STRING, BASE_NONE, NULL, 0x00,
6111                                 "WSP header Accept-Language", HFILL
6112                         }
6113                 },
6114                 { &hf_hdr_accept_ranges,
6115                         {       "Accept-Ranges",
6116                                 "wsp.header.accept_ranges",
6117                                 FT_STRING, BASE_NONE, NULL, 0x00,
6118                                 "WSP header Accept-Ranges", HFILL
6119                         }
6120                 },
6121                 { &hf_hdr_age,
6122                         {       "Age",
6123                                 "wsp.header.age",
6124                                 FT_STRING, BASE_NONE, NULL, 0x00,
6125                                 "WSP header Age", HFILL
6126                         }
6127                 },
6128                 { &hf_hdr_allow,
6129                         {       "Allow",
6130                                 "wsp.header.allow",
6131                                 FT_STRING, BASE_NONE, NULL, 0x00,
6132                                 "WSP header Allow", HFILL
6133                         }
6134                 },
6135                 { &hf_hdr_authorization,
6136                         {       "Authorization",
6137                                 "wsp.header.authorization",
6138                                 FT_STRING, BASE_NONE, NULL, 0x00,
6139                                 "WSP header Authorization", HFILL
6140                         }
6141                 },
6142                 { &hf_hdr_authorization_scheme,
6143                         {       "Authorization Scheme",
6144                                 "wsp.header.authorization.scheme",
6145                                 FT_STRING, BASE_NONE, NULL, 0x00,
6146                                 "WSP header Authorization: used scheme", HFILL
6147                         }
6148                 },
6149                 { &hf_hdr_authorization_user_id,
6150                         {       "User-id",
6151                                 "wsp.header.authorization.user_id",
6152                                 FT_STRING, BASE_NONE, NULL, 0x00,
6153                                 "WSP header Authorization: user ID for basic authorization", HFILL
6154                         }
6155                 },
6156                 { &hf_hdr_authorization_password,
6157                         {       "Password",
6158                                 "wsp.header.authorization.password",
6159                                 FT_STRING, BASE_NONE, NULL, 0x00,
6160                                 "WSP header Authorization: password for basic authorization", HFILL
6161                         }
6162                 },
6163                 { &hf_hdr_cache_control,
6164                         {       "Cache-Control",
6165                                 "wsp.header.cache_control",
6166                                 FT_STRING, BASE_NONE, NULL, 0x00,
6167                                 "WSP header Cache-Control", HFILL
6168                         }
6169                 },
6170                 { &hf_hdr_connection,
6171                         {       "Connection",
6172                                 "wsp.header.connection",
6173                                 FT_STRING, BASE_NONE, NULL, 0x00,
6174                                 "WSP header Connection", HFILL
6175                         }
6176                 },
6177                 { &hf_hdr_content_base,
6178                         {       "Content-Base",
6179                                 "wsp.header.content_base",
6180                                 FT_STRING, BASE_NONE, NULL, 0x00,
6181                                 "WSP header Content-Base", HFILL
6182                         }
6183                 },
6184                 { &hf_hdr_content_encoding,
6185                         {       "Content-Encoding",
6186                                 "wsp.header.content_encoding",
6187                                 FT_STRING, BASE_NONE, NULL, 0x00,
6188                                 "WSP header Content-Encoding", HFILL
6189                         }
6190                 },
6191                 { &hf_hdr_content_language,
6192                         {       "Content-Language",
6193                                 "wsp.header.content_language",
6194                                 FT_STRING, BASE_NONE, NULL, 0x00,
6195                                 "WSP header Content-Language", HFILL
6196                         }
6197                 },
6198                 { &hf_hdr_content_length,
6199                         {       "Content-Length",
6200                                 "wsp.header.content_length",
6201                                 FT_STRING, BASE_NONE, NULL, 0x00,
6202                                 "WSP header Content-Length", HFILL
6203                         }
6204                 },
6205                 { &hf_hdr_content_location,
6206                         {       "Content-Location",
6207                                 "wsp.header.content_location",
6208                                 FT_STRING, BASE_NONE, NULL, 0x00,
6209                                 "WSP header Content-Location", HFILL
6210                         }
6211                 },
6212                 { &hf_hdr_content_md5,
6213                         {       "Content-Md5",
6214                                 "wsp.header.content_md5",
6215                                 FT_STRING, BASE_NONE, NULL, 0x00,
6216                                 "WSP header Content-Md5", HFILL
6217                         }
6218                 },
6219                 { &hf_hdr_content_range,
6220                         {       "Content-Range",
6221                                 "wsp.header.content_range",
6222                                 FT_STRING, BASE_NONE, NULL, 0x00,
6223                                 "WSP header Content-Range", HFILL
6224                         }
6225                 },
6226                 { &hf_hdr_content_range_first_byte_pos,
6227                         {       "First-byte-position",
6228                                 "wsp.header.content_range.first_byte_pos",
6229                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6230                                 "WSP header Content-Range: position of first byte", HFILL
6231                         }
6232                 },
6233                 { &hf_hdr_content_range_entity_length,
6234                         {       "Entity-length",
6235                                 "wsp.header.content_range.entity_length",
6236                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6237                                 "WSP header Content-Range: length of the entity", HFILL
6238                         }
6239                 },
6240                 { &hf_hdr_content_type,
6241                         {       "Content-Type",
6242                                 "wsp.header.content_type",
6243                                 FT_STRING, BASE_NONE, NULL, 0x00,
6244                                 "WSP header Content-Type", HFILL
6245                         }
6246                 },
6247                 { &hf_hdr_date,
6248                         {       "Date",
6249                                 "wsp.header.date",
6250                                 FT_STRING, BASE_NONE, NULL, 0x00,
6251                                 "WSP header Date", HFILL
6252                         }
6253                 },
6254                 { &hf_hdr_etag,
6255                         {       "ETag",
6256                                 "wsp.header.etag",
6257                                 FT_STRING, BASE_NONE, NULL, 0x00,
6258                                 "WSP header ETag", HFILL
6259                         }
6260                 },
6261                 { &hf_hdr_expires,
6262                         {       "Expires",
6263                                 "wsp.header.expires",
6264                                 FT_STRING, BASE_NONE, NULL, 0x00,
6265                                 "WSP header Expires", HFILL
6266                         }
6267                 },
6268                 { &hf_hdr_from,
6269                         {       "From",
6270                                 "wsp.header.from",
6271                                 FT_STRING, BASE_NONE, NULL, 0x00,
6272                                 "WSP header From", HFILL
6273                         }
6274                 },
6275                 { &hf_hdr_host,
6276                         {       "Host",
6277                                 "wsp.header.host",
6278                                 FT_STRING, BASE_NONE, NULL, 0x00,
6279                                 "WSP header Host", HFILL
6280                         }
6281                 },
6282                 { &hf_hdr_if_modified_since,
6283                         {       "If-Modified-Since",
6284                                 "wsp.header.if_modified_since",
6285                                 FT_STRING, BASE_NONE, NULL, 0x00,
6286                                 "WSP header If-Modified-Since", HFILL
6287                         }
6288                 },
6289                 { &hf_hdr_if_match,
6290                         {       "If-Match",
6291                                 "wsp.header.if_match",
6292                                 FT_STRING, BASE_NONE, NULL, 0x00,
6293                                 "WSP header If-Match", HFILL
6294                         }
6295                 },
6296                 { &hf_hdr_if_none_match,
6297                         {       "If-None-Match",
6298                                 "wsp.header.if_none_match",
6299                                 FT_STRING, BASE_NONE, NULL, 0x00,
6300                                 "WSP header If-None-Match", HFILL
6301                         }
6302                 },
6303                 { &hf_hdr_if_range,
6304                         {       "If-Range",
6305                                 "wsp.header.if_range",
6306                                 FT_STRING, BASE_NONE, NULL, 0x00,
6307                                 "WSP header If-Range", HFILL
6308                         }
6309                 },
6310                 { &hf_hdr_if_unmodified_since,
6311                         {       "If-Unmodified-Since",
6312                                 "wsp.header.if_unmodified_since",
6313                                 FT_STRING, BASE_NONE, NULL, 0x00,
6314                                 "WSP header If-Unmodified-Since", HFILL
6315                         }
6316                 },
6317                 { &hf_hdr_last_modified,
6318                         {       "Last-Modified",
6319                                 "wsp.header.last_modified",
6320                                 FT_STRING, BASE_NONE, NULL, 0x00,
6321                                 "WSP header Last-Modified", HFILL
6322                         }
6323                 },
6324                 { &hf_hdr_location,
6325                         {       "Location",
6326                                 "wsp.header.location",
6327                                 FT_STRING, BASE_NONE, NULL, 0x00,
6328                                 "WSP header Location", HFILL
6329                         }
6330                 },
6331                 { &hf_hdr_max_forwards,
6332                         {       "Max-Forwards",
6333                                 "wsp.header.max_forwards",
6334                                 FT_STRING, BASE_NONE, NULL, 0x00,
6335                                 "WSP header Max-Forwards", HFILL
6336                         }
6337                 },
6338                 { &hf_hdr_pragma,
6339                         {       "Pragma",
6340                                 "wsp.header.pragma",
6341                                 FT_STRING, BASE_NONE, NULL, 0x00,
6342                                 "WSP header Pragma", HFILL
6343                         }
6344                 },
6345                 { &hf_hdr_proxy_authenticate,
6346                         {       "Proxy-Authenticate",
6347                                 "wsp.header.proxy_authenticate",
6348                                 FT_STRING, BASE_NONE, NULL, 0x00,
6349                                 "WSP header Proxy-Authenticate", HFILL
6350                         }
6351                 },
6352                 { &hf_hdr_proxy_authenticate_scheme,
6353                         {       "Authentication Scheme",
6354                                 "wsp.header.proxy_authenticate.scheme",
6355                                 FT_STRING, BASE_NONE, NULL, 0x00,
6356                                 "WSP header Proxy-Authenticate: used scheme", HFILL
6357                         }
6358                 },
6359                 { &hf_hdr_proxy_authenticate_realm,
6360                         {       "Authentication Realm",
6361                                 "wsp.header.proxy_authenticate.realm",
6362                                 FT_STRING, BASE_NONE, NULL, 0x00,
6363                                 "WSP header Proxy-Authenticate: used realm", HFILL
6364                         }
6365                 },
6366                 { &hf_hdr_proxy_authorization,
6367                         {       "Proxy-Authorization",
6368                                 "wsp.header.proxy_authorization",
6369                                 FT_STRING, BASE_NONE, NULL, 0x00,
6370                                 "WSP header Proxy-Authorization", HFILL
6371                         }
6372                 },
6373                 { &hf_hdr_proxy_authorization_scheme,
6374                         {       "Authorization Scheme",
6375                                 "wsp.header.proxy_authorization.scheme",
6376                                 FT_STRING, BASE_NONE, NULL, 0x00,
6377                                 "WSP header Proxy-Authorization: used scheme", HFILL
6378                         }
6379                 },
6380                 { &hf_hdr_proxy_authorization_user_id,
6381                         {       "User-id",
6382                                 "wsp.header.proxy_authorization.user_id",
6383                                 FT_STRING, BASE_NONE, NULL, 0x00,
6384                                 "WSP header Proxy-Authorization: user ID for basic authorization", HFILL
6385                         }
6386                 },
6387                 { &hf_hdr_proxy_authorization_password,
6388                         {       "Password",
6389                                 "wsp.header.proxy_authorization.password",
6390                                 FT_STRING, BASE_NONE, NULL, 0x00,
6391                                 "WSP header Proxy-Authorization: password for basic authorization", HFILL
6392                         }
6393                 },
6394                 { &hf_hdr_public,
6395                         {       "Public",
6396                                 "wsp.header.public",
6397                                 FT_STRING, BASE_NONE, NULL, 0x00,
6398                                 "WSP header Public", HFILL
6399                         }
6400                 },
6401                 { &hf_hdr_range,
6402                         {       "Range",
6403                                 "wsp.header.range",
6404                                 FT_STRING, BASE_NONE, NULL, 0x00,
6405                                 "WSP header Range", HFILL
6406                         }
6407                 },
6408                 { &hf_hdr_range_first_byte_pos,
6409                         {       "First-byte-position",
6410                                 "wsp.header.range.first_byte_pos",
6411                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6412                                 "WSP header Range: position of first byte", HFILL
6413                         }
6414                 },
6415                 { &hf_hdr_range_last_byte_pos,
6416                         {       "Last-byte-position",
6417                                 "wsp.header.range.last_byte_pos",
6418                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6419                                 "WSP header Range: position of last byte", HFILL
6420                         }
6421                 },
6422                 { &hf_hdr_range_suffix_length,
6423                         {       "Suffix-length",
6424                                 "wsp.header.range.suffix_length",
6425                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6426                                 "WSP header Range: length of the suffix", HFILL
6427                         }
6428                 },
6429                 { &hf_hdr_referer,
6430                         {       "Referer",
6431                                 "wsp.header.referer",
6432                                 FT_STRING, BASE_NONE, NULL, 0x00,
6433                                 "WSP header Referer", HFILL
6434                         }
6435                 },
6436                 { &hf_hdr_retry_after,
6437                         {       "Retry-After",
6438                                 "wsp.header.retry_after",
6439                                 FT_STRING, BASE_NONE, NULL, 0x00,
6440                                 "WSP header Retry-After", HFILL
6441                         }
6442                 },
6443                 { &hf_hdr_server,
6444                         {       "Server",
6445                                 "wsp.header.server",
6446                                 FT_STRING, BASE_NONE, NULL, 0x00,
6447                                 "WSP header Server", HFILL
6448                         }
6449                 },
6450                 { &hf_hdr_transfer_encoding,
6451                         {       "Transfer-Encoding",
6452                                 "wsp.header.transfer_encoding",
6453                                 FT_STRING, BASE_NONE, NULL, 0x00,
6454                                 "WSP header Transfer-Encoding", HFILL
6455                         }
6456                 },
6457                 { &hf_hdr_upgrade,
6458                         {       "Upgrade",
6459                                 "wsp.header.upgrade",
6460                                 FT_STRING, BASE_NONE, NULL, 0x00,
6461                                 "WSP header Upgrade", HFILL
6462                         }
6463                 },
6464                 { &hf_hdr_user_agent,
6465                         {       "User-Agent",
6466                                 "wsp.header.user_agent",
6467                                 FT_STRING, BASE_NONE, NULL, 0x00,
6468                                 "WSP header User-Agent", HFILL
6469                         }
6470                 },
6471                 { &hf_hdr_vary,
6472                         {       "Vary",
6473                                 "wsp.header.vary",
6474                                 FT_STRING, BASE_NONE, NULL, 0x00,
6475                                 "WSP header Vary", HFILL
6476                         }
6477                 },
6478                 { &hf_hdr_via,
6479                         {       "Via",
6480                                 "wsp.header.via",
6481                                 FT_STRING, BASE_NONE, NULL, 0x00,
6482                                 "WSP header Via", HFILL
6483                         }
6484                 },
6485                 { &hf_hdr_warning,
6486                         {       "Warning",
6487                                 "wsp.header.warning",
6488                                 FT_STRING, BASE_NONE, NULL, 0x00,
6489                                 "WSP header Warning", HFILL
6490                         }
6491                 },
6492                 { &hf_hdr_warning_code,
6493                         {       "Warning code",
6494                                 "wsp.header.warning.code",
6495                                 FT_UINT8, BASE_HEX, VALS(vals_wsp_warning_code), 0x00,
6496                                 "WSP header Warning code", HFILL
6497                         }
6498                 },
6499                 { &hf_hdr_warning_agent,
6500                         {       "Warning agent",
6501                                 "wsp.header.warning.agent",
6502                                 FT_STRING, BASE_NONE, NULL, 0x00,
6503                                 "WSP header Warning agent", HFILL
6504                         }
6505                 },
6506                 { &hf_hdr_warning_text,
6507                         {       "Warning text",
6508                                 "wsp.header.warning.text",
6509                                 FT_STRING, BASE_NONE, NULL, 0x00,
6510                                 "WSP header Warning text", HFILL
6511                         }
6512                 },
6513                 { &hf_hdr_www_authenticate,
6514                         {       "Www-Authenticate",
6515                                 "wsp.header.www_authenticate",
6516                                 FT_STRING, BASE_NONE, NULL, 0x00,
6517                                 "WSP header Www-Authenticate", HFILL
6518                         }
6519                 },
6520                 { &hf_hdr_www_authenticate_scheme,
6521                         {       "Authentication Scheme",
6522                                 "wsp.header.www_authenticate.scheme",
6523                                 FT_STRING, BASE_NONE, NULL, 0x00,
6524                                 "WSP header WWW-Authenticate: used scheme", HFILL
6525                         }
6526                 },
6527                 { &hf_hdr_www_authenticate_realm,
6528                         {       "Authentication Realm",
6529                                 "wsp.header.www_authenticate.realm",
6530                                 FT_STRING, BASE_NONE, NULL, 0x00,
6531                                 "WSP header WWW-Authenticate: used realm", HFILL
6532                         }
6533                 },
6534                 { &hf_hdr_content_disposition,
6535                         {       "Content-Disposition",
6536                                 "wsp.header.content_disposition",
6537                                 FT_STRING, BASE_NONE, NULL, 0x00,
6538                                 "WSP header Content-Disposition", HFILL
6539                         }
6540                 },
6541                 { &hf_hdr_application_id,
6542                         {       "Application-Id",
6543                                 "wsp.header.application_id",
6544                                 FT_STRING, BASE_NONE, NULL, 0x00,
6545                                 "WSP header Application-Id", HFILL
6546                         }
6547                 },
6548                 { &hf_hdr_content_uri,
6549                         {       "Content-Uri",
6550                                 "wsp.header.content_uri",
6551                                 FT_STRING, BASE_NONE, NULL, 0x00,
6552                                 "WSP header Content-Uri", HFILL
6553                         }
6554                 },
6555                 { &hf_hdr_initiator_uri,
6556                         {       "Initiator-Uri",
6557                                 "wsp.header.initiator_uri",
6558                                 FT_STRING, BASE_NONE, NULL, 0x00,
6559                                 "WSP header Initiator-Uri", HFILL
6560                         }
6561                 },
6562                 { &hf_hdr_bearer_indication,
6563                         {       "Bearer-Indication",
6564                                 "wsp.header.bearer_indication",
6565                                 FT_STRING, BASE_NONE, NULL, 0x00,
6566                                 "WSP header Bearer-Indication", HFILL
6567                         }
6568                 },
6569                 { &hf_hdr_push_flag,
6570                         {       "Push-Flag",
6571                                 "wsp.header.push_flag",
6572                                 FT_STRING, BASE_NONE, NULL, 0x00,
6573                                 "WSP header Push-Flag", HFILL
6574                         }
6575                 },
6576                 { &hf_hdr_push_flag_auth,
6577                         {       "Initiator URI is authenticated",
6578                                 "wsp.header.push_flag.authenticated",
6579                                 FT_UINT8, BASE_DEC, VALS(vals_false_true), 0x01,
6580                                 "The X-Wap-Initiator-URI has been authenticated.", HFILL
6581                         }
6582                 },
6583                 { &hf_hdr_push_flag_trust,
6584                         {       "Content is trusted",
6585                                 "wsp.header.push_flag.trusted",
6586                                 FT_UINT8, BASE_DEC, VALS(vals_false_true), 0x02,
6587                                 "The push content is trusted.", HFILL
6588                         }
6589                 },
6590                 { &hf_hdr_push_flag_last,
6591                         {       "Last push message",
6592                                 "wsp.header.push_flag.last",
6593                                 FT_UINT8, BASE_DEC, VALS(vals_false_true), 0x04,
6594                                 "Indicates whether this is the last push message.", HFILL
6595                         }
6596                 },
6597                 { &hf_hdr_profile,
6598                         {       "Profile",
6599                                 "wsp.header.profile",
6600                                 FT_STRING, BASE_NONE, NULL, 0x00,
6601                                 "WSP header Profile", HFILL
6602                         }
6603                 },
6604                 { &hf_hdr_profile_diff,
6605                         {       "Profile-Diff",
6606                                 "wsp.header.profile_diff",
6607                                 FT_STRING, BASE_NONE, NULL, 0x00,
6608                                 "WSP header Profile-Diff", HFILL
6609                         }
6610                 },
6611                 { &hf_hdr_profile_warning,
6612                         {       "Profile-Warning",
6613                                 "wsp.header.profile_warning",
6614                                 FT_STRING, BASE_NONE, NULL, 0x00,
6615                                 "WSP header Profile-Warning", HFILL
6616                         }
6617                 },
6618                 { &hf_hdr_expect,
6619                         {       "Expect",
6620                                 "wsp.header.expect",
6621                                 FT_STRING, BASE_NONE, NULL, 0x00,
6622                                 "WSP header Expect", HFILL
6623                         }
6624                 },
6625                 { &hf_hdr_te,
6626                         {       "Te",
6627                                 "wsp.header.te",
6628                                 FT_STRING, BASE_NONE, NULL, 0x00,
6629                                 "WSP header Te", HFILL
6630                         }
6631                 },
6632                 { &hf_hdr_trailer,
6633                         {       "Trailer",
6634                                 "wsp.header.trailer",
6635                                 FT_STRING, BASE_NONE, NULL, 0x00,
6636                                 "WSP header Trailer", HFILL
6637                         }
6638                 },
6639                 { &hf_hdr_x_wap_tod,
6640                         {       "X-Wap-Tod",
6641                                 "wsp.header.x_wap_tod",
6642                                 FT_STRING, BASE_NONE, NULL, 0x00,
6643                                 "WSP header X-Wap-Tod", HFILL
6644                         }
6645                 },
6646                 { &hf_hdr_content_id,
6647                         {       "Content-Id",
6648                                 "wsp.header.content_id",
6649                                 FT_STRING, BASE_NONE, NULL, 0x00,
6650                                 "WSP header Content-Id", HFILL
6651                         }
6652                 },
6653                 { &hf_hdr_set_cookie,
6654                         {       "Set-Cookie",
6655                                 "wsp.header.set_cookie",
6656                                 FT_STRING, BASE_NONE, NULL, 0x00,
6657                                 "WSP header Set-Cookie", HFILL
6658                         }
6659                 },
6660                 { &hf_hdr_cookie,
6661                         {       "Cookie",
6662                                 "wsp.header.cookie",
6663                                 FT_STRING, BASE_NONE, NULL, 0x00,
6664                                 "WSP header Cookie", HFILL
6665                         }
6666                 },
6667                 { &hf_hdr_encoding_version,
6668                         {       "Encoding-Version",
6669                                 "wsp.header.encoding_version",
6670                                 FT_STRING, BASE_NONE, NULL, 0x00,
6671                                 "WSP header Encoding-Version", HFILL
6672                         }
6673                 },
6674                 { &hf_hdr_x_wap_security,
6675                         {       "X-Wap-Security",
6676                                 "wsp.header.x_wap_security",
6677                                 FT_STRING, BASE_NONE, NULL, 0x00,
6678                                 "WSP header X-Wap-Security", HFILL
6679                         }
6680                 },
6681                 { &hf_hdr_x_wap_application_id,
6682                         {       "X-Wap-Application-Id",
6683                                 "wsp.header.x_wap_application_id",
6684                                 FT_STRING, BASE_NONE, NULL, 0x00,
6685                                 "WSP header X-Wap-Application-Id", HFILL
6686                         }
6687                 },
6688                 { &hf_hdr_accept_application,
6689                         {       "Accept-Application",
6690                                 "wsp.header.accept_application",
6691                                 FT_STRING, BASE_NONE, NULL, 0x00,
6692                                 "WSP header Accept-Application", HFILL
6693                         }
6694                 },
6695
6696
6697                 /*
6698                  * Openwave headers
6699                  * Header Code Page: x-up-1
6700                  */
6701
6702                 /* Textual headers */
6703                 { &hf_hdr_openwave_x_up_proxy_operator_domain,
6704                         {       "x-up-proxy-operator-domain",
6705                                 "wsp.header.x_up_1.x_up_proxy_operator_domain",
6706                                 FT_STRING, BASE_NONE, NULL, 0x00,
6707                                 "WSP Openwave header x-up-proxy-operator-domain", HFILL
6708                         }
6709                 },
6710                 { &hf_hdr_openwave_x_up_proxy_home_page,
6711                         {       "x-up-proxy-home-page",
6712                                 "wsp.header.x_up_1.x_up_proxy_home_page",
6713                                 FT_STRING, BASE_NONE, NULL, 0x00,
6714                                 "WSP Openwave header x-up-proxy-home-page", HFILL
6715                         }
6716                 },
6717                 { &hf_hdr_openwave_x_up_proxy_uplink_version,
6718                         {       "x-up-proxy-uplink-version",
6719                                 "wsp.header.x_up_1.x_up_proxy_uplink_version",
6720                                 FT_STRING, BASE_NONE, NULL, 0x00,
6721                                 "WSP Openwave header x-up-proxy-uplink-version", HFILL
6722                         }
6723                 },
6724                 { &hf_hdr_openwave_x_up_proxy_ba_realm,
6725                         {       "x-up-proxy-ba-realm",
6726                                 "wsp.header.x_up_1.x_up_proxy_ba_realm",
6727                                 FT_STRING, BASE_NONE, NULL, 0x00,
6728                                 "WSP Openwave header x-up-proxy-ba-realm", HFILL
6729                         }
6730                 },
6731                 { &hf_hdr_openwave_x_up_proxy_request_uri,
6732                         {       "x-up-proxy-request-uri",
6733                                 "wsp.header.x_up_1.x_up_proxy_request_uri",
6734                                 FT_STRING, BASE_NONE, NULL, 0x00,
6735                                 "WSP Openwave header x-up-proxy-request-uri", HFILL
6736                         }
6737                 },
6738                 { &hf_hdr_openwave_x_up_proxy_bookmark,
6739                         {       "x-up-proxy-bookmark",
6740                                 "wsp.header.x_up_1.x_up_proxy_bookmark",
6741                                 FT_STRING, BASE_NONE, NULL, 0x00,
6742                                 "WSP Openwave header x-up-proxy-bookmark", HFILL
6743                         }
6744                 },
6745                 /* Integer-value headers */
6746                 { &hf_hdr_openwave_x_up_proxy_push_seq,
6747                         {       "x-up-proxy-push-seq",
6748                                 "wsp.header.x_up_1.x_up_proxy_push_seq",
6749                                 FT_STRING, BASE_NONE, NULL, 0x00,
6750                                 "WSP Openwave header x-up-proxy-push-seq", HFILL
6751                         }
6752                 },
6753                 { &hf_hdr_openwave_x_up_proxy_notify,
6754                         {       "x-up-proxy-notify",
6755                                 "wsp.header.x_up_1.x_up_proxy_notify",
6756                                 FT_STRING, BASE_NONE, NULL, 0x00,
6757                                 "WSP Openwave header x-up-proxy-notify", HFILL
6758                         }
6759                 },
6760                 { &hf_hdr_openwave_x_up_proxy_net_ask,
6761                         {       "x-up-proxy-net-ask",
6762                                 "wsp.header.x_up_1.x_up_proxy_net_ask",
6763                                 FT_STRING, BASE_NONE, NULL, 0x00,
6764                                 "WSP Openwave header x-up-proxy-net-ask", HFILL
6765                         }
6766                 },
6767                 { &hf_hdr_openwave_x_up_proxy_tod,
6768                         {       "x-up-proxy-tod",
6769                                 "wsp.header.x_up_1.x_up_proxy_tod",
6770                                 FT_STRING, BASE_NONE, NULL, 0x00,
6771                                 "WSP Openwave header x-up-proxy-tod", HFILL
6772                         }
6773                 },
6774                 { &hf_hdr_openwave_x_up_proxy_ba_enable,
6775                         {       "x-up-proxy-ba-enable",
6776                                 "wsp.header.x_up_1.x_up_proxy_ba_enable",
6777                                 FT_STRING, BASE_NONE, NULL, 0x00,
6778                                 "WSP Openwave header x-up-proxy-ba-enable", HFILL
6779                         }
6780                 },
6781                 { &hf_hdr_openwave_x_up_proxy_redirect_enable,
6782                         {       "x-up-proxy-redirect-enable",
6783                                 "wsp.header.x_up_1.x_up_proxy_redirect_enable",
6784                                 FT_STRING, BASE_NONE, NULL, 0x00,
6785                                 "WSP Openwave header x-up-proxy-redirect-enable", HFILL
6786                         }
6787                 },
6788                 { &hf_hdr_openwave_x_up_proxy_redirect_status,
6789                         {       "x-up-proxy-redirect-status",
6790                                 "wsp.header.x_up_1.x_up_proxy_redirect_status",
6791                                 FT_STRING, BASE_NONE, NULL, 0x00,
6792                                 "WSP Openwave header x-up-proxy-redirect-status", HFILL
6793                         }
6794                 },
6795                 { &hf_hdr_openwave_x_up_proxy_linger,
6796                         {       "x-up-proxy-linger",
6797                                 "wsp.header.x_up_1.x_up_proxy_linger",
6798                                 FT_STRING, BASE_NONE, NULL, 0x00,
6799                                 "WSP Openwave header x-up-proxy-linger", HFILL
6800                         }
6801                 },
6802                 { &hf_hdr_openwave_x_up_proxy_enable_trust,
6803                         {       "x-up-proxy-enable-trust",
6804                                 "wsp.header.x_up_1.x_up_proxy_enable_trust",
6805                                 FT_STRING, BASE_NONE, NULL, 0x00,
6806                                 "WSP Openwave header x-up-proxy-enable-trust", HFILL
6807                         }
6808                 },
6809                 { &hf_hdr_openwave_x_up_proxy_trust,
6810                         {       "x-up-proxy-trust",
6811                                 "wsp.header.x_up_1.x_up_proxy_trust",
6812                                 FT_STRING, BASE_NONE, NULL, 0x00,
6813                                 "WSP Openwave header x-up-proxy-trust", HFILL
6814                         }
6815                 },
6816                 { &hf_hdr_openwave_x_up_devcap_has_color,
6817                         {       "x-up-devcap-has-color",
6818                                 "wsp.header.x_up_1.x_up_devcap_has_color",
6819                                 FT_STRING, BASE_NONE, NULL, 0x00,
6820                                 "WSP Openwave header x-up-devcap-has-color", HFILL
6821                         }
6822                 },
6823                 { &hf_hdr_openwave_x_up_devcap_num_softkeys,
6824                         {       "x-up-devcap-num-softkeys",
6825                                 "wsp.header.x_up_1.x_up_devcap_num_softkeys",
6826                                 FT_STRING, BASE_NONE, NULL, 0x00,
6827                                 "WSP Openwave header x-up-devcap-num-softkeys", HFILL
6828                         }
6829                 },
6830                 { &hf_hdr_openwave_x_up_devcap_softkey_size,
6831                         {       "x-up-devcap-softkey-size",
6832                                 "wsp.header.x_up_1.x_up_devcap_softkey_size",
6833                                 FT_STRING, BASE_NONE, NULL, 0x00,
6834                                 "WSP Openwave header x-up-devcap-softkey-size", HFILL
6835                         }
6836                 },
6837                 { &hf_hdr_openwave_x_up_devcap_screen_chars,
6838                         {       "x-up-devcap-screen-chars",
6839                                 "wsp.header.x_up_1.x_up_devcap_screen_chars",
6840                                 FT_STRING, BASE_NONE, NULL, 0x00,
6841                                 "WSP Openwave header x-up-devcap-screen-chars", HFILL
6842                         }
6843                 },
6844                 { &hf_hdr_openwave_x_up_devcap_screen_pixels,
6845                         {       "x-up-devcap-screen-pixels",
6846                                 "wsp.header.x_up_1.x_up_devcap_screen_pixels",
6847                                 FT_STRING, BASE_NONE, NULL, 0x00,
6848                                 "WSP Openwave header x-up-devcap-screen-pixels", HFILL
6849                         }
6850                 },
6851                 { &hf_hdr_openwave_x_up_devcap_em_size,
6852                         {       "x-up-devcap-em-size",
6853                                 "wsp.header.x_up_1.x_up_devcap_em_size",
6854                                 FT_STRING, BASE_NONE, NULL, 0x00,
6855                                 "WSP Openwave header x-up-devcap-em-size", HFILL
6856                         }
6857                 },
6858                 { &hf_hdr_openwave_x_up_devcap_screen_depth,
6859                         {       "x-up-devcap-screen-depth",
6860                                 "wsp.header.x_up_1.x_up_devcap_screen_depth",
6861                                 FT_STRING, BASE_NONE, NULL, 0x00,
6862                                 "WSP Openwave header x-up-devcap-screen-depth", HFILL
6863                         }
6864                 },
6865                 { &hf_hdr_openwave_x_up_devcap_immed_alert,
6866                         {       "x-up-devcap-immed-alert",
6867                                 "wsp.header.x_up_1.x_up_devcap_immed_alert",
6868                                 FT_STRING, BASE_NONE, NULL, 0x00,
6869                                 "WSP Openwave header x-up-devcap-immed-alert", HFILL
6870                         }
6871                 },
6872                 { &hf_hdr_openwave_x_up_devcap_gui,
6873                         {       "x-up-devcap-gui",
6874                                 "wsp.header.x_up_1.x_up_devcap_gui",
6875                                 FT_STRING, BASE_NONE, NULL, 0x00,
6876                                 "WSP Openwave header x-up-devcap-gui", HFILL
6877                         }
6878                 },
6879                 { &hf_hdr_openwave_x_up_proxy_trans_charset,
6880                         {       "x-up-proxy-trans-charset",
6881                                 "wsp.header.x_up_1.x_up_proxy_trans_charset",
6882                                 FT_STRING, BASE_NONE, NULL, 0x00,
6883                                 "WSP Openwave header x-up-proxy-trans-charset", HFILL
6884                         }
6885                 },
6886                 { &hf_hdr_openwave_x_up_proxy_push_accept,
6887                         {       "x-up-proxy-push-accept",
6888                                 "wsp.header.x_up_1.x_up_proxy_push_accept",
6889                                 FT_STRING, BASE_NONE, NULL, 0x00,
6890                                 "WSP Openwave header x-up-proxy-push-accept", HFILL
6891                         }
6892                 },
6893
6894                 /* Not used for now
6895                 { &hf_hdr_openwave_x_up_proxy_client_id,
6896                         {       "x-up-proxy-client-id",
6897                                 "wsp.header.x_up_1.x_up_proxy_client_id",
6898                                 FT_STRING, BASE_NONE, NULL, 0x00,
6899                                 "WSP Openwave header x-up-proxy-client-id", HFILL
6900                         }
6901                 },
6902                 */
6903
6904                 /*
6905                  * Header value parameters
6906                  */
6907
6908                 { &hf_parameter_q,
6909                         {       "Q",
6910                                 "wsp.parameter.q",
6911                                  FT_STRING, BASE_NONE, NULL, 0x00,
6912                                 "Q parameter", HFILL
6913                         }
6914                 },
6915                 { &hf_parameter_charset,
6916                         {       "Charset",
6917                                 "wsp.parameter.charset",
6918                                  FT_STRING, BASE_NONE, NULL, 0x00,
6919                                 "Charset parameter", HFILL
6920                         }
6921                 },
6922
6923                 /*
6924                  * Session Initiation Request
6925                  */
6926                 { &hf_sir_section,
6927                         {       "Session Initiation Request",
6928                                 "wsp.sir",
6929                                 FT_NONE, BASE_NONE, NULL, 0x00,
6930                                 "Session Initiation Request content", HFILL
6931                         }
6932                 },
6933                 { &hf_sir_version,
6934                         {       "Version",
6935                                 "wsp.sir.version",
6936                                 FT_UINT8, BASE_DEC, NULL, 0x00,
6937                                 "Version of the Session Initiation Request document", HFILL
6938                         }
6939                 },
6940                 { &hf_sir_app_id_list_len,
6941                         {       "Application-ID List Length",
6942                                 "wsp.sir.app_id_list.length",
6943                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6944                                 "Length of the Application-ID list (bytes)", HFILL
6945                         }
6946                 },
6947                 { &hf_sir_app_id_list,
6948                         {       "Application-ID List",
6949                                 "wsp.sir.app_id_list",
6950                                 FT_NONE, BASE_NONE, NULL, 0x00,
6951                                 "Application-ID list", HFILL
6952                         }
6953                 },
6954                 { &hf_sir_wsp_contact_points_len,
6955                         {       "WSP Contact Points Length",
6956                                 "wsp.sir.wsp_contact_points.length",
6957                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6958                                 "Length of the WSP Contact Points list (bytes)", HFILL
6959                         }
6960                 },
6961                 { &hf_sir_wsp_contact_points,
6962                         {       "WSP Contact Points",
6963                                 "wsp.sir.wsp_contact_points",
6964                                 FT_NONE, BASE_NONE, NULL, 0x00,
6965                                 "WSP Contact Points list", HFILL
6966                         }
6967                 },
6968                 { &hf_sir_contact_points_len,
6969                         {       "Non-WSP Contact Points Length",
6970                                 "wsp.sir.contact_points.length",
6971                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6972                                 "Length of the Non-WSP Contact Points list (bytes)", HFILL
6973                         }
6974                 },
6975                 { &hf_sir_contact_points,
6976                         {       "Non-WSP Contact Points",
6977                                 "wsp.sir.contact_points",
6978                                 FT_NONE, BASE_NONE, NULL, 0x00,
6979                                 "Non-WSP Contact Points list", HFILL
6980                         }
6981                 },
6982                 { &hf_sir_protocol_options_len,
6983                         {       "Protocol Options List Entries",
6984                                 "wsp.sir.protocol_options.length",
6985                                 FT_UINT32, BASE_DEC, NULL, 0x00,
6986                                 "Number of entries in the Protocol Options list", HFILL
6987                         }
6988                 },
6989                 { &hf_sir_protocol_options,
6990                         {       "Protocol Options",
6991                                 "wsp.sir.protocol_options",
6992                                 FT_UINT16, BASE_DEC, VALS(vals_sir_protocol_options), 0x00,
6993                                 "Protocol Options list", HFILL
6994                         }
6995                 },
6996                 { &hf_sir_prov_url_len,
6997                         {       "X-Wap-ProvURL Length",
6998                                 "wsp.sir.prov_url.length",
6999                                 FT_UINT32, BASE_DEC, NULL, 0x00,
7000                                 "Length of the X-Wap-ProvURL (Identifies the WAP Client Provisioning Context)", HFILL
7001                         }
7002                 },
7003                 { &hf_sir_prov_url,
7004                         {       "X-Wap-ProvURL",
7005                                 "wsp.sir.prov_url",
7006                                 FT_STRING, BASE_NONE, NULL, 0x00,
7007                                 "X-Wap-ProvURL (Identifies the WAP Client Provisioning Context)", HFILL
7008                         }
7009                 },
7010                 { &hf_sir_cpi_tag_len,
7011                         {       "CPITag List Entries",
7012                                 "wsp.sir.cpi_tag.length",
7013                                 FT_UINT32, BASE_DEC, NULL, 0x00,
7014                                 "Number of entries in the CPITag list", HFILL
7015                         }
7016                 },
7017                 { &hf_sir_cpi_tag,
7018                         {       "CPITag",
7019                                 "wsp.sir.cpi_tag",
7020                                 FT_BYTES, BASE_HEX, NULL, 0x00,
7021                                 "CPITag (OTA-HTTP)", HFILL
7022                         }
7023                 },
7024
7025
7026         };
7027
7028
7029 /* Setup protocol subtree array */
7030         static gint *ett[] = { /* TODO - remove unneeded subtrees */
7031                 &ett_wsp,
7032                 &ett_header, /* Header field subtree */
7033                 &ett_headers, /* Subtree for WSP headers */
7034                 &ett_capabilities, /* CO-WSP Session Capabilities */
7035                 &ett_capability, /* CO-WSP Session single Capability */
7036                 &ett_post,
7037                 &ett_redirect_flags,
7038                 &ett_address_flags,
7039                 &ett_multiparts,
7040                 &ett_mpartlist,
7041                 &ett_sir,                       /* Session Initiation Request */
7042                 &ett_addresses,         /* Addresses */
7043                 &ett_address,           /* Single address */
7044         };
7045
7046 /* Register the protocol name and description */
7047         proto_wsp = proto_register_protocol(
7048                 "Wireless Session Protocol",    /* protocol name for use by ethereal */
7049                 "WSP",                          /* short version of name */
7050                 "wsp"                               /* Abbreviated protocol name,
7051                                                                                    should Match IANA:
7052             < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
7053                                                                                 */
7054         );
7055         wsp_tap = register_tap("wsp");
7056         /* Init the hash table */
7057 /*      wsp_sessions = g_hash_table_new(
7058                         (GHashFunc) wsp_session_hash,
7059                         (GEqualFunc)wsp_session_equal);*/
7060
7061 /* Required function calls to register the header fields and subtrees used  */
7062         proto_register_field_array(proto_wsp, hf, array_length(hf));
7063         proto_register_subtree_array(ett, array_length(ett));
7064
7065         register_dissector("wsp-co", dissect_wsp_fromwap_co, proto_wsp);
7066         register_dissector("wsp-cl", dissect_wsp_fromwap_cl, proto_wsp);
7067         /* As the media types for WSP and HTTP are the same, the WSP dissector
7068          * uses the same string dissector table as the HTTP protocol. */
7069         media_type_table = find_dissector_table("media_type");
7070         register_heur_dissector_list("wsp", &heur_subdissector_list);
7071
7072         wsp_fromudp_handle = create_dissector_handle(dissect_wsp_fromudp,
7073             proto_wsp);
7074 }
7075
7076 void
7077 proto_reg_handoff_wsp(void)
7078 {
7079         /*
7080          * And get a handle for the WTP-over-UDP dissector.
7081          */
7082         wtp_fromudp_handle = find_dissector("wtp-udp");
7083
7084         /* Only connection-less WSP has no previous handler */
7085         dissector_add("udp.port", UDP_PORT_WSP, wsp_fromudp_handle);
7086         dissector_add("udp.port", UDP_PORT_WSP_PUSH, wsp_fromudp_handle);
7087
7088         /* SMPP dissector can also carry WSP */
7089         dissector_add("smpp.udh.port", UDP_PORT_WSP, wsp_fromudp_handle);
7090         dissector_add("smpp.udh.port", UDP_PORT_WSP_PUSH, wsp_fromudp_handle);
7091
7092         /* This dissector is also called from the WTP and WTLS dissectors */
7093 }