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