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