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