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