46e481602d037ee51941c1bea96f292ebf20f4f3
[obnox/wireshark/wip.git] / packet-wsp.c
1 /* packet-wsp.c
2  *
3  * Routines to dissect WSP component of WAP traffic.
4  *
5  * $Id: packet-wsp.c,v 1.101 2003/12/22 22:57:09 obiot Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * WAP dissector based on original work by Ben Fowler
12  * Updated by Neil Hunter <neil.hunter@energis-squared.com>
13  * WTLS support by Alexandre P. Ferreira (Splice IP)
14  * Openwave header support by Dermot Bradley <dermot.bradley@openwave.com>
15  * Code optimizations, header value dissection simplification with parse error
16  * notification and macros, extra missing headers, WBXML registration,
17  * Session Initiation Request dissection
18  * by Olivier Biot <olivier.biot(ad)siemens.com>.
19  *
20  * TODO - Move parts of dissection before and other parts after "if (tree)",
21  * for example skip almost all but content type in replies if tree is closed.
22  *
23  * This program is free software; you can redistribute it and/or
24  * modify it under the terms of the GNU General Public License
25  * as published by the Free Software Foundation; either version 2
26  * of the License, or (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  */
37
38 /* Edit with a 4-space tabulation */
39
40 #ifdef HAVE_CONFIG_H
41 # include "config.h"
42 #endif
43
44 #include <stdio.h>
45 #include <stdlib.h>
46
47 #ifdef NEED_SNPRINTF_H
48 # include "snprintf.h"
49 #endif
50
51 #include <string.h>
52 #include <glib.h>
53 #include <epan/packet.h>
54 #include <epan/ipv6-utils.h>
55 #include <epan/conversation.h>
56
57 #include "packet-wap.h"
58 #include "packet-wsp.h"
59
60 #define PLURALIZE(x)    ( (x) == 1 ? "" : "s" )
61
62 /* General-purpose debug logger.
63  * Requires double parentheses because of variable arguments of printf().
64  *
65  * Enable debug logging for WSP by defining AM_CFLAGS
66  * so that it contains "-DDEBUG_wsp"
67  */
68 #ifdef DEBUG_wsp
69 #define DebugLog(x) \
70         printf("%s:%u: ", __FILE__, __LINE__); \
71         printf x; \
72         fflush(stdout)
73 #else
74 #define DebugLog(x) ;
75 #endif
76
77 /* Statistics (see doc/README.tapping) */
78 #include "tap.h"
79 static int wsp_tap = -1;
80
81
82 /* File scoped variables for the protocol and registered fields */
83 static int proto_wsp                                    = HF_EMPTY;
84 static int proto_sir                                    = HF_EMPTY;
85
86 /*
87  * Initialize the header field pointers
88  */
89
90 /* WSP header fields and their subfields if available */
91 static int hf_hdr_name                                  = HF_EMPTY;
92 static int hf_hdr_accept                                = HF_EMPTY;
93 static int hf_hdr_accept_charset                = HF_EMPTY;
94 static int hf_hdr_accept_encoding               = HF_EMPTY;
95 static int hf_hdr_accept_language               = HF_EMPTY;
96 static int hf_hdr_accept_ranges                 = HF_EMPTY;
97 static int hf_hdr_age                                   = HF_EMPTY;
98 static int hf_hdr_allow                                 = HF_EMPTY;
99 static int hf_hdr_authorization                 = HF_EMPTY;
100 static int hf_hdr_authorization_scheme                  = HF_EMPTY; /* Subfield */
101 static int hf_hdr_authorization_user_id                 = HF_EMPTY; /* Subfield */
102 static int hf_hdr_authorization_password                = HF_EMPTY; /* Subfield */
103 static int hf_hdr_cache_control                 = HF_EMPTY;
104 static int hf_hdr_connection                    = HF_EMPTY;
105 static int hf_hdr_content_base                  = HF_EMPTY;
106 static int hf_hdr_content_encoding              = HF_EMPTY;
107 static int hf_hdr_content_language              = HF_EMPTY;
108 static int hf_hdr_content_length                = HF_EMPTY;
109 static int hf_hdr_content_location              = HF_EMPTY;
110 static int hf_hdr_content_md5                   = HF_EMPTY;
111 static int hf_hdr_content_range                 = HF_EMPTY;
112 static int hf_hdr_content_range_first_byte_pos  = HF_EMPTY; /* Subfield */
113 static int hf_hdr_content_range_entity_length   = HF_EMPTY; /* Subfield */
114 static int hf_hdr_content_type                  = HF_EMPTY;
115 static int hf_hdr_date                                  = HF_EMPTY;
116 static int hf_hdr_etag                                  = HF_EMPTY;
117 static int hf_hdr_expires                               = HF_EMPTY;
118 static int hf_hdr_from                                  = HF_EMPTY;
119 static int hf_hdr_host                                  = HF_EMPTY;
120 static int hf_hdr_if_modified_since             = HF_EMPTY;
121 static int hf_hdr_if_match                              = HF_EMPTY;
122 static int hf_hdr_if_none_match                 = HF_EMPTY;
123 static int hf_hdr_if_range                              = HF_EMPTY;
124 static int hf_hdr_if_unmodified_since   = HF_EMPTY;
125 static int hf_hdr_last_modified                 = HF_EMPTY;
126 static int hf_hdr_location                              = HF_EMPTY;
127 static int hf_hdr_max_forwards                  = HF_EMPTY;
128 static int hf_hdr_pragma                                = HF_EMPTY;
129 static int hf_hdr_proxy_authenticate    = HF_EMPTY;
130 static int hf_hdr_proxy_authenticate_scheme             = HF_EMPTY; /* Subfield */
131 static int hf_hdr_proxy_authenticate_realm              = HF_EMPTY; /* Subfield */
132 static int hf_hdr_proxy_authorization   = HF_EMPTY;
133 static int hf_hdr_proxy_authorization_scheme    = HF_EMPTY; /* Subfield */
134 static int hf_hdr_proxy_authorization_user_id   = HF_EMPTY; /* Subfield */
135 static int hf_hdr_proxy_authorization_password  = HF_EMPTY; /* Subfield */
136 static int hf_hdr_public                                = HF_EMPTY;
137 static int hf_hdr_range                                 = HF_EMPTY;
138 static int hf_hdr_range_first_byte_pos                  = HF_EMPTY; /* Subfield */
139 static int hf_hdr_range_last_byte_pos                   = HF_EMPTY; /* Subfield */
140 static int hf_hdr_range_suffix_length                   = HF_EMPTY; /* Subfield */
141 static int hf_hdr_referer                               = HF_EMPTY;
142 static int hf_hdr_retry_after                   = HF_EMPTY;
143 static int hf_hdr_server                                = HF_EMPTY;
144 static int hf_hdr_transfer_encoding             = HF_EMPTY;
145 static int hf_hdr_upgrade                               = HF_EMPTY;
146 static int hf_hdr_user_agent                    = HF_EMPTY;
147 static int hf_hdr_vary                                  = HF_EMPTY;
148 static int hf_hdr_via                                   = HF_EMPTY;
149 static int hf_hdr_warning                               = HF_EMPTY;
150 static int hf_hdr_warning_code                                  = HF_EMPTY; /* Subfield */
151 static int hf_hdr_warning_agent                                 = HF_EMPTY; /* Subfield */
152 static int hf_hdr_warning_text                                  = HF_EMPTY; /* Subfield */
153 static int hf_hdr_www_authenticate              = HF_EMPTY;
154 static int hf_hdr_www_authenticate_scheme               = HF_EMPTY; /* Subfield */
155 static int hf_hdr_www_authenticate_realm                = HF_EMPTY; /* Subfield */
156 static int hf_hdr_content_disposition   = HF_EMPTY;
157 static int hf_hdr_application_id                = HF_EMPTY;
158 static int hf_hdr_content_uri                   = HF_EMPTY;
159 static int hf_hdr_initiator_uri                 = HF_EMPTY;
160 static int hf_hdr_bearer_indication             = HF_EMPTY;
161 static int hf_hdr_push_flag                             = HF_EMPTY;
162 static int hf_hdr_push_flag_auth                                = HF_EMPTY; /* Subfield */
163 static int hf_hdr_push_flag_trust                               = HF_EMPTY; /* Subfield */
164 static int hf_hdr_push_flag_last                                = HF_EMPTY; /* Subfield */
165 static int hf_hdr_profile                               = HF_EMPTY;
166 static int hf_hdr_profile_diff                  = HF_EMPTY;
167 static int hf_hdr_profile_warning               = HF_EMPTY;
168 static int hf_hdr_expect                                = HF_EMPTY;
169 static int hf_hdr_te                                    = HF_EMPTY;
170 static int hf_hdr_trailer                               = HF_EMPTY;
171 static int hf_hdr_x_wap_tod                             = HF_EMPTY;
172 static int hf_hdr_content_id                    = HF_EMPTY;
173 static int hf_hdr_set_cookie                    = HF_EMPTY;
174 static int hf_hdr_cookie                                = HF_EMPTY;
175 static int hf_hdr_encoding_version              = HF_EMPTY;
176 static int hf_hdr_x_wap_security                = HF_EMPTY;
177 static int hf_hdr_x_wap_application_id  = HF_EMPTY;
178 static int hf_hdr_accept_application    = HF_EMPTY;
179
180
181 /* Openwave headers */
182 static int hf_hdr_openwave_x_up_proxy_operator_domain   = HF_EMPTY;
183 static int hf_hdr_openwave_x_up_proxy_home_page                 = HF_EMPTY;
184 static int hf_hdr_openwave_x_up_proxy_uplink_version    = HF_EMPTY;
185 static int hf_hdr_openwave_x_up_proxy_ba_realm                  = HF_EMPTY;
186 static int hf_hdr_openwave_x_up_proxy_request_uri               = HF_EMPTY;
187 #if 0
188 static int hf_hdr_openwave_x_up_proxy_client_id                 = HF_EMPTY;
189 #endif
190 static int hf_hdr_openwave_x_up_proxy_bookmark                  = HF_EMPTY;
191 static int hf_hdr_openwave_x_up_proxy_push_seq                  = HF_EMPTY;
192 static int hf_hdr_openwave_x_up_proxy_notify                    = HF_EMPTY;
193 static int hf_hdr_openwave_x_up_proxy_net_ask                   = HF_EMPTY;
194 static int hf_hdr_openwave_x_up_proxy_tod                               = HF_EMPTY;
195 static int hf_hdr_openwave_x_up_proxy_ba_enable                 = HF_EMPTY;
196 static int hf_hdr_openwave_x_up_proxy_redirect_enable   = HF_EMPTY;
197 static int hf_hdr_openwave_x_up_proxy_redirect_status   = HF_EMPTY;
198 static int hf_hdr_openwave_x_up_proxy_linger                    = HF_EMPTY;
199 static int hf_hdr_openwave_x_up_proxy_enable_trust              = HF_EMPTY;
200 static int hf_hdr_openwave_x_up_proxy_trust                             = HF_EMPTY;
201 static int hf_hdr_openwave_x_up_devcap_has_color                = HF_EMPTY;
202 static int hf_hdr_openwave_x_up_devcap_num_softkeys             = HF_EMPTY;
203 static int hf_hdr_openwave_x_up_devcap_softkey_size             = HF_EMPTY;
204 static int hf_hdr_openwave_x_up_devcap_screen_chars             = HF_EMPTY;
205 static int hf_hdr_openwave_x_up_devcap_screen_pixels    = HF_EMPTY;
206 static int hf_hdr_openwave_x_up_devcap_em_size                  = HF_EMPTY;
207 static int hf_hdr_openwave_x_up_devcap_screen_depth             = HF_EMPTY;
208 static int hf_hdr_openwave_x_up_devcap_immed_alert              = HF_EMPTY;
209 static int hf_hdr_openwave_x_up_devcap_gui                              = HF_EMPTY;
210 static int hf_hdr_openwave_x_up_proxy_trans_charset             = HF_EMPTY;
211 static int hf_hdr_openwave_x_up_proxy_push_accept               = HF_EMPTY;
212
213
214 /* WSP parameter fields */
215 static int hf_parameter_q                                       = HF_EMPTY;
216 static int hf_parameter_charset                         = HF_EMPTY;
217 #if 0
218 static int hf_parameter_textual                         = HF_EMPTY;
219 static int hf_parameter_type                            = HF_EMPTY;
220 static int hf_parameter_name                            = HF_EMPTY;
221 static int hf_parameter_filename                        = HF_EMPTY;
222 static int hf_parameter_start                           = HF_EMPTY;
223 static int hf_parameter_start_info                      = HF_EMPTY;
224 static int hf_parameter_comment                         = HF_EMPTY;
225 static int hf_parameter_domain                          = HF_EMPTY;
226 static int hf_parameter_path                            = HF_EMPTY;
227 static int hf_parameter_sec                                     = HF_EMPTY;
228 static int hf_parameter_mac                                     = HF_EMPTY;
229 static int hf_parameter_upart_type                      = HF_EMPTY;
230 static int hf_parameter_upart_type_value        = HF_EMPTY;
231 static int hf_parameter_level                           = HF_EMPTY;
232 #endif
233
234 /* Old header fields */
235
236 static int hf_wsp_header_tid                            = HF_EMPTY;
237 static int hf_wsp_header_pdu_type                       = HF_EMPTY;
238 static int hf_wsp_version_major                         = HF_EMPTY;
239 static int hf_wsp_version_minor                         = HF_EMPTY;
240 /* Session capabilities (CO-WSP) */
241 static int hf_capabilities_length               = HF_EMPTY;
242 static int hf_capabilities_section              = HF_EMPTY;
243 static int hf_capa_client_sdu_size              = HF_EMPTY;
244 static int hf_capa_server_sdu_size              = HF_EMPTY;
245 static int hf_capa_protocol_options             = HF_EMPTY;
246 static int hf_capa_protocol_option_confirmed_push               = HF_EMPTY; /* Subfield */
247 static int hf_capa_protocol_option_push                                 = HF_EMPTY; /* Subfield */
248 static int hf_capa_protocol_option_session_resume               = HF_EMPTY; /* Subfield */
249 static int hf_capa_protocol_option_ack_headers                  = HF_EMPTY; /* Subfield */
250 static int hf_capa_protocol_option_large_data_transfer  = HF_EMPTY; /* Subfield */
251 static int hf_capa_method_mor                   = HF_EMPTY;
252 static int hf_capa_push_mor                             = HF_EMPTY;
253 static int hf_capa_extended_methods             = HF_EMPTY;
254 static int hf_capa_header_code_pages    = HF_EMPTY;
255 static int hf_capa_aliases                              = HF_EMPTY;
256 static int hf_capa_client_message_size  = HF_EMPTY;
257 static int hf_capa_server_message_size  = HF_EMPTY;
258
259 static int hf_wsp_header_uri_len                        = HF_EMPTY;
260 static int hf_wsp_header_uri                            = HF_EMPTY;
261 static int hf_wsp_server_session_id                     = HF_EMPTY;
262 static int hf_wsp_header_status                         = HF_EMPTY;
263 static int hf_wsp_header_length                         = HF_EMPTY;
264 static int hf_wsp_headers_section                       = HF_EMPTY;
265 static int hf_wsp_parameter_type                        = HF_EMPTY;
266 static int hf_wsp_parameter_name                        = HF_EMPTY;
267 static int hf_wsp_parameter_filename                    = HF_EMPTY;
268 static int hf_wsp_parameter_start                       = HF_EMPTY;
269 static int hf_wsp_parameter_start_info                  = HF_EMPTY;
270 static int hf_wsp_parameter_comment                     = HF_EMPTY;
271 static int hf_wsp_parameter_domain                      = HF_EMPTY;
272 static int hf_wsp_parameter_path                        = HF_EMPTY;
273 static int hf_wsp_parameter_sec                 = HF_EMPTY;
274 static int hf_wsp_parameter_mac                 = HF_EMPTY;
275 static int hf_wsp_parameter_upart_type                  = HF_EMPTY;
276 static int hf_wsp_parameter_level                       = HF_EMPTY;
277 static int hf_wsp_reply_data                            = HF_EMPTY;
278 static int hf_wsp_post_data                             = HF_EMPTY;
279 static int hf_wsp_push_data                             = HF_EMPTY;
280 static int hf_wsp_multipart_data                        = HF_EMPTY;
281 static int hf_wsp_mpart                                 = HF_EMPTY;
282
283 /* Header code page shift sequence */
284 static int hf_wsp_header_shift_code                     = HF_EMPTY;
285
286 /* WSP Redirect fields */
287 static int hf_wsp_redirect_flags                                        = HF_EMPTY;
288 static int hf_wsp_redirect_permanent                            = HF_EMPTY;
289 static int hf_wsp_redirect_reuse_security_session       = HF_EMPTY;
290 static int hf_redirect_addresses                                        = HF_EMPTY;
291
292 /* Address fields */
293 static int hf_address_entry                             = HF_EMPTY;
294 static int hf_address_flags_length              = HF_EMPTY;
295 static int hf_address_flags_length_bearer_type_included = HF_EMPTY; /* Subfield */
296 static int hf_address_flags_length_port_number_included = HF_EMPTY; /* Subfield */
297 static int hf_address_flags_length_address_len                  = HF_EMPTY; /* Subfield */
298 static int hf_address_bearer_type               = HF_EMPTY;
299 static int hf_address_port_num                  = HF_EMPTY;
300 static int hf_address_ipv4_addr                 = HF_EMPTY;
301 static int hf_address_ipv6_addr                 = HF_EMPTY;
302 static int hf_address_addr                              = HF_EMPTY;
303
304 /* Session Initiation Request fields */
305 static int hf_sir_section                                       = HF_EMPTY;
306 static int hf_sir_version                                       = HF_EMPTY;
307 static int hf_sir_app_id_list_len                       = HF_EMPTY;
308 static int hf_sir_app_id_list                           = HF_EMPTY;
309 static int hf_sir_wsp_contact_points_len        = HF_EMPTY;
310 static int hf_sir_wsp_contact_points            = HF_EMPTY;
311 static int hf_sir_contact_points_len            = HF_EMPTY;
312 static int hf_sir_contact_points                        = HF_EMPTY;
313 static int hf_sir_protocol_options_len          = HF_EMPTY;
314 static int hf_sir_protocol_options                      = HF_EMPTY;
315 static int hf_sir_prov_url_len                          = HF_EMPTY;
316 static int hf_sir_prov_url                                      = HF_EMPTY;
317 static int hf_sir_cpi_tag_len                           = HF_EMPTY;
318 static int hf_sir_cpi_tag                                       = HF_EMPTY;
319
320 /*
321  * Initialize the subtree pointers
322  */
323
324 /* WSP tree */
325 static int ett_wsp                                              = ETT_EMPTY;
326 /* WSP headers tree */
327 static int ett_header                                   = ETT_EMPTY;
328 /* WSP header subtree */
329 static int ett_headers                                  = ETT_EMPTY;
330 /* CO-WSP session capabilities */
331 static int ett_capabilities                             = ETT_EMPTY;
332 static int ett_capability                               = ETT_EMPTY;
333 static int ett_post                                             = ETT_EMPTY;
334 static int ett_redirect_flags                   = ETT_EMPTY;
335 static int ett_address_flags                    = ETT_EMPTY;
336 static int ett_multiparts                               = ETT_EMPTY;
337 static int ett_mpartlist                                = ETT_EMPTY;
338 /* Session Initiation Request tree */
339 static int ett_sir                                              = ETT_EMPTY;
340 static int ett_addresses                                = ETT_EMPTY;
341 static int ett_address                                  = ETT_EMPTY;
342
343
344
345 /* Handle for WSP-over-UDP dissector */
346 static dissector_handle_t wsp_fromudp_handle;
347
348 /* Handle for WTP-over-UDP dissector */
349 static dissector_handle_t wtp_fromudp_handle;
350
351 const value_string vals_pdu_type[] = {
352         { 0x00, "Reserved" },
353         { 0x01, "Connect" },
354         { 0x02, "ConnectReply" },
355         { 0x03, "Redirect" },
356         { 0x04, "Reply" },
357         { 0x05, "Disconnect" },
358         { 0x06, "Push" },
359         { 0x07, "ConfirmedPush" },
360         { 0x08, "Suspend" },
361         { 0x09, "Resume" },
362
363         /* 0x10 - 0x3F Unassigned */
364
365         { 0x40, "Get" },
366         { 0x41, "Options" },
367         { 0x42, "Head" },
368         { 0x43, "Delete" },
369         { 0x44, "Trace" },
370
371         /* 0x45 - 0x4F Unassigned (Get PDU) */
372         /* 0x50 - 0x5F Extended method (Get PDU) */
373         { 0x50, "Extended Get Method 0"},
374         { 0x51, "Extended Get Method 1"},
375         { 0x52, "Extended Get Method 2"},
376         { 0x53, "Extended Get Method 3"},
377         { 0x54, "Extended Get Method 4"},
378         { 0x55, "Extended Get Method 5"},
379         { 0x56, "Extended Get Method 6"},
380         { 0x57, "Extended Get Method 7"},
381         { 0x58, "Extended Get Method 8"},
382         { 0x59, "Extended Get Method 9"},
383         { 0x5A, "Extended Get Method 10"},
384         { 0x5B, "Extended Get Method 11"},
385         { 0x5C, "Extended Get Method 12"},
386         { 0x5D, "Extended Get Method 13"},
387         { 0x5E, "Extended Get Method 14"},
388         { 0x5F, "Extended Get Method 15"},
389
390         { 0x60, "Post" },
391         { 0x61, "Put" },
392
393         /* 0x62 - 0x6F Unassigned (Post PDU) */
394         /* 0x70 - 0x7F Extended method (Post PDU) */
395         { 0x70, "Extended Post Method 0"},
396         { 0x71, "Extended Post Method 1"},
397         { 0x72, "Extended Post Method 2"},
398         { 0x73, "Extended Post Method 3"},
399         { 0x74, "Extended Post Method 4"},
400         { 0x75, "Extended Post Method 5"},
401         { 0x76, "Extended Post Method 6"},
402         { 0x77, "Extended Post Method 7"},
403         { 0x78, "Extended Post Method 8"},
404         { 0x79, "Extended Post Method 9"},
405         { 0x7A, "Extended Post Method 10"},
406         { 0x7B, "Extended Post Method 11"},
407         { 0x7C, "Extended Post Method 12"},
408         { 0x7D, "Extended Post Method 13"},
409         { 0x7E, "Extended Post Method 14"},
410         { 0x7F, "Extended Post Method 15"},
411
412         /* 0x80 - 0xFF Reserved */
413
414         { 0x00, NULL }
415
416 };
417
418 /* The WSP status codes are inherited from the HTTP status codes */
419 const value_string vals_status[] = {
420         /* 0x00 - 0x0F Reserved */
421
422         { 0x10, "100 Continue" },
423         { 0x11, "101 Switching Protocols" },
424
425         { 0x20, "200 OK" },
426         { 0x21, "201 Created" },
427         { 0x22, "202 Accepted" },
428         { 0x23, "203 Non-Authoritative Information" },
429         { 0x24, "204 No Content" },
430         { 0x25, "205 Reset Content" },
431         { 0x26, "206 Partial Content" },
432
433         { 0x30, "300 Multiple Choices" },
434         { 0x31, "301 Moved Permanently" },
435         { 0x32, "302 Moved Temporarily" },
436         { 0x33, "303 See Other" },
437         { 0x34, "304 Not Modified" },
438         { 0x35, "305 Use Proxy" },
439         { 0x37, "307 Temporary Redirect" },
440
441         { 0x40, "400 Bad Request" },
442         { 0x41, "401 Unauthorised" },
443         { 0x42, "402 Payment Required" },
444         { 0x43, "403 Forbidden" },
445         { 0x44, "404 Not Found" },
446         { 0x45, "405 Method Not Allowed" },
447         { 0x46, "406 Not Acceptable" },
448         { 0x47, "407 Proxy Authentication Required" },
449         { 0x48, "408 Request Timeout" },
450         { 0x49, "409 Conflict" },
451         { 0x4A, "410 Gone" },
452         { 0x4B, "411 Length Required" },
453         { 0x4C, "412 Precondition Failed" },
454         { 0x4D, "413 Request Entity Too Large" },
455         { 0x4E, "414 Request-URI Too Large" },
456         { 0x4F, "415 Unsupported Media Type" },
457         { 0x50, "416 Requested Range Not Satisfiable" },
458         { 0x51, "417 Expectation Failed" },
459
460         { 0x60, "500 Internal Server Error" },
461         { 0x61, "501 Not Implemented" },
462         { 0x62, "502 Bad Gateway" },
463         { 0x63, "503 Service Unavailable" },
464         { 0x64, "504 Gateway Timeout" },
465         { 0x65, "505 WSP/HTTP Version Not Supported" },
466
467         { 0x00, NULL }
468 };
469
470 const value_string vals_wsp_reason_codes[] = {
471         { 0xE0, "Protocol Error (Illegal PDU)" },
472         { 0xE1, "Session disconnected" },
473         { 0xE2, "Session suspended" },
474         { 0xE3, "Session resumed" },
475         { 0xE4, "Peer congested" },
476         { 0xE5, "Session connect failed" },
477         { 0xE6, "Maximum receive unit size exceeded" },
478         { 0xE7, "Maximum outstanding requests exceeded" },
479         { 0xE8, "Peer request" },
480         { 0xE9, "Network error" },
481         { 0xEA, "User request" },
482         { 0xEB, "No specific cause, no retries" },
483         { 0xEC, "Push message cannot be delivered" },
484         { 0xED, "Push message discarded" },
485         { 0xEE, "Content type cannot be processed" },
486
487         { 0x00, NULL }
488 };
489
490 /*
491  * Field names.
492  */
493 #define FN_ACCEPT               0x00
494 #define FN_ACCEPT_CHARSET_DEP   0x01    /* encoding version 1.1, deprecated */
495 #define FN_ACCEPT_ENCODING_DEP  0x02    /* encoding version 1.1, deprecated */
496 #define FN_ACCEPT_LANGUAGE      0x03
497 #define FN_ACCEPT_RANGES        0x04
498 #define FN_AGE                  0x05
499 #define FN_ALLOW                0x06
500 #define FN_AUTHORIZATION        0x07
501 #define FN_CACHE_CONTROL_DEP    0x08    /* encoding version 1.1, deprecated */
502 #define FN_CONNECTION           0x09
503 #define FN_CONTENT_BASE         0x0A
504 #define FN_CONTENT_ENCODING     0x0B
505 #define FN_CONTENT_LANGUAGE     0x0C
506 #define FN_CONTENT_LENGTH       0x0D
507 #define FN_CONTENT_LOCATION     0x0E
508 #define FN_CONTENT_MD5          0x0F
509 #define FN_CONTENT_RANGE_DEP    0x10    /* encoding version 1.1, deprecated */
510 #define FN_CONTENT_TYPE         0x11
511 #define FN_DATE                 0x12
512 #define FN_ETAG                 0x13
513 #define FN_EXPIRES              0x14
514 #define FN_FROM                 0x15
515 #define FN_HOST                 0x16
516 #define FN_IF_MODIFIED_SINCE    0x17
517 #define FN_IF_MATCH             0x18
518 #define FN_IF_NONE_MATCH        0x19
519 #define FN_IF_RANGE             0x1A
520 #define FN_IF_UNMODIFIED_SINCE  0x1B
521 #define FN_LOCATION             0x1C
522 #define FN_LAST_MODIFIED        0x1D
523 #define FN_MAX_FORWARDS         0x1E
524 #define FN_PRAGMA               0x1F
525 #define FN_PROXY_AUTHENTICATE   0x20
526 #define FN_PROXY_AUTHORIZATION  0x21
527 #define FN_PUBLIC               0x22
528 #define FN_RANGE                0x23
529 #define FN_REFERER              0x24
530 #define FN_RETRY_AFTER          0x25
531 #define FN_SERVER               0x26
532 #define FN_TRANSFER_ENCODING    0x27
533 #define FN_UPGRADE              0x28
534 #define FN_USER_AGENT           0x29
535 #define FN_VARY                 0x2A
536 #define FN_VIA                  0x2B
537 #define FN_WARNING              0x2C
538 #define FN_WWW_AUTHENTICATE     0x2D
539 #define FN_CONTENT_DISPOSITION  0x2E
540 #define FN_X_WAP_APPLICATION_ID 0x2F
541 #define FN_X_WAP_CONTENT_URI    0x30
542 #define FN_X_WAP_INITIATOR_URI  0x31
543 #define FN_ACCEPT_APPLICATION   0x32
544 #define FN_BEARER_INDICATION    0x33
545 #define FN_PUSH_FLAG            0x34
546 #define FN_PROFILE              0x35
547 #define FN_PROFILE_DIFF         0x36
548 #define FN_PROFILE_WARNING      0x37
549 #define FN_EXPECT               0x38
550 #define FN_TE                   0x39
551 #define FN_TRAILER              0x3A
552 #define FN_ACCEPT_CHARSET       0x3B    /* encoding version 1.3 */
553 #define FN_ACCEPT_ENCODING      0x3C    /* encoding version 1.3 */
554 #define FN_CACHE_CONTROL        0x3D    /* encoding version 1.3 */
555 #define FN_CONTENT_RANGE        0x3E    /* encoding version 1.3 */
556 #define FN_X_WAP_TOD            0x3F
557 #define FN_CONTENT_ID           0x40
558 #define FN_SET_COOKIE           0x41
559 #define FN_COOKIE               0x42
560 #define FN_ENCODING_VERSION     0x43
561 #define FN_PROFILE_WARNING14    0x44    /* encoding version 1.4 */
562 #define FN_CONTENT_DISPOSITION14        0x45    /* encoding version 1.4 */
563 #define FN_X_WAP_SECURITY       0x46
564 #define FN_CACHE_CONTROL14      0x47    /* encoding version 1.4 */
565 #define FN_EXPECT15 0x48        /* encoding version 1.5 */
566 #define FN_X_WAP_LOC_INVOCATION 0x49
567 #define FN_X_WAP_LOC_DELIVERY 0x4A
568
569
570 /*
571  * Openwave field names.
572  */
573 #define FN_OPENWAVE_PROXY_PUSH_ADDR             0x00
574 #define FN_OPENWAVE_PROXY_PUSH_ACCEPT           0x01
575 #define FN_OPENWAVE_PROXY_PUSH_SEQ              0x02
576 #define FN_OPENWAVE_PROXY_NOTIFY                0x03
577 #define FN_OPENWAVE_PROXY_OPERATOR_DOMAIN       0x04
578 #define FN_OPENWAVE_PROXY_HOME_PAGE             0x05
579 #define FN_OPENWAVE_DEVCAP_HAS_COLOR            0x06
580 #define FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS         0x07
581 #define FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE         0x08
582 #define FN_OPENWAVE_DEVCAP_SCREEN_CHARS         0x09
583 #define FN_OPENWAVE_DEVCAP_SCREEN_PIXELS        0x0A
584 #define FN_OPENWAVE_DEVCAP_EM_SIZE              0x0B
585 #define FN_OPENWAVE_DEVCAP_SCREEN_DEPTH         0x0C
586 #define FN_OPENWAVE_DEVCAP_IMMED_ALERT          0x0D
587 #define FN_OPENWAVE_PROXY_NET_ASK               0x0E
588 #define FN_OPENWAVE_PROXY_UPLINK_VERSION        0x0F
589 #define FN_OPENWAVE_PROXY_TOD                   0x10
590 #define FN_OPENWAVE_PROXY_BA_ENABLE             0x11
591 #define FN_OPENWAVE_PROXY_BA_REALM              0x12
592 #define FN_OPENWAVE_PROXY_REDIRECT_ENABLE       0x13
593 #define FN_OPENWAVE_PROXY_REQUEST_URI           0x14
594 #define FN_OPENWAVE_PROXY_REDIRECT_STATUS       0x15
595 #define FN_OPENWAVE_PROXY_TRANS_CHARSET         0x16
596 #define FN_OPENWAVE_PROXY_LINGER                0x17
597 #define FN_OPENWAVE_PROXY_CLIENT_ID             0x18
598 #define FN_OPENWAVE_PROXY_ENABLE_TRUST          0x19
599 #define FN_OPENWAVE_PROXY_TRUST_OLD             0x1A
600 #define FN_OPENWAVE_PROXY_TRUST                 0x20
601 #define FN_OPENWAVE_PROXY_BOOKMARK              0x21
602 #define FN_OPENWAVE_DEVCAP_GUI                  0x22
603
604 static const value_string vals_openwave_field_names[] = {
605         { FN_OPENWAVE_PROXY_PUSH_ADDR,         "x-up-proxy-push-addr" },
606         { FN_OPENWAVE_PROXY_PUSH_ACCEPT,       "x-up-proxy-push-accept" },
607         { FN_OPENWAVE_PROXY_PUSH_SEQ,          "x-up-proxy-seq" },
608         { FN_OPENWAVE_PROXY_NOTIFY,            "x-up-proxy-notify" },
609         { FN_OPENWAVE_PROXY_OPERATOR_DOMAIN,   "x-up-proxy-operator-domain" },
610         { FN_OPENWAVE_PROXY_HOME_PAGE,         "x-up-proxy-home-page" },
611         { FN_OPENWAVE_DEVCAP_HAS_COLOR,        "x-up-devcap-has-color" },
612         { FN_OPENWAVE_DEVCAP_NUM_SOFTKEYS,     "x-up-devcap-num-softkeys" },
613         { FN_OPENWAVE_DEVCAP_SOFTKEY_SIZE,     "x-up-devcap-softkey-size" },
614         { FN_OPENWAVE_DEVCAP_SCREEN_CHARS,     "x-up-devcap-screen-chars" },
615         { FN_OPENWAVE_DEVCAP_SCREEN_PIXELS,    "x-up-devcap-screen-pixels" },
616         { FN_OPENWAVE_DEVCAP_EM_SIZE,          "x-up-devcap-em-size" },
617         { FN_OPENWAVE_DEVCAP_SCREEN_DEPTH,     "x-up-devcap-screen-depth" },
618         { FN_OPENWAVE_DEVCAP_IMMED_ALERT,      "x-up-devcap-immed-alert" },
619         { FN_OPENWAVE_PROXY_NET_ASK,           "x-up-proxy-net-ask" },
620         { FN_OPENWAVE_PROXY_UPLINK_VERSION,    "x-up-proxy-uplink-version" },
621         { FN_OPENWAVE_PROXY_TOD,               "x-up-proxy-tod" },
622         { FN_OPENWAVE_PROXY_BA_ENABLE,         "x-up-proxy-ba-enable" },
623         { FN_OPENWAVE_PROXY_BA_REALM,          "x-up-proxy-ba-realm" },
624         { FN_OPENWAVE_PROXY_REDIRECT_ENABLE,   "x-up-proxy-redirect-enable" },
625         { FN_OPENWAVE_PROXY_REQUEST_URI,       "x-up-proxy-request-uri" },
626         { FN_OPENWAVE_PROXY_REDIRECT_STATUS,   "x-up-proxy-redirect-status" },
627         { FN_OPENWAVE_PROXY_TRANS_CHARSET,     "x-up-proxy-trans-charset" },
628         { FN_OPENWAVE_PROXY_LINGER,            "x-up-proxy-linger" },
629         { FN_OPENWAVE_PROXY_CLIENT_ID,         "x-up-proxy-client-id" },
630         { FN_OPENWAVE_PROXY_ENABLE_TRUST,      "x-up-proxy-enable-trust" },
631         { FN_OPENWAVE_PROXY_TRUST_OLD,         "x-up-proxy-trust-old" },
632         { FN_OPENWAVE_PROXY_TRUST,             "x-up-proxy-trust" },
633         { FN_OPENWAVE_PROXY_BOOKMARK,          "x-up-proxy-bookmark" },
634         { FN_OPENWAVE_DEVCAP_GUI,              "x-up-devcap-gui" },
635         { 0,                                   NULL }
636 };
637
638
639 static const value_string vals_field_names[] = {
640         { FN_ACCEPT,               "Accept" },
641         { FN_ACCEPT_CHARSET_DEP,   "Accept-Charset (encoding 1.1)" },
642         { FN_ACCEPT_ENCODING_DEP,  "Accept-Encoding (encoding 1.1)" },
643         { FN_ACCEPT_LANGUAGE,      "Accept-Language" },
644         { FN_ACCEPT_RANGES,        "Accept-Ranges" },
645         { FN_AGE,                  "Age" },
646         { FN_ALLOW,                "Allow" },
647         { FN_AUTHORIZATION,        "Authorization" },
648         { FN_CACHE_CONTROL_DEP,    "Cache-Control (encoding 1.1)" },
649         { FN_CONNECTION,           "Connection" },
650         { FN_CONTENT_BASE,         "Content-Base" },
651         { FN_CONTENT_ENCODING,     "Content-Encoding" },
652         { FN_CONTENT_LANGUAGE,     "Content-Language" },
653         { FN_CONTENT_LENGTH,       "Content-Length" },
654         { FN_CONTENT_LOCATION,     "Content-Location" },
655         { FN_CONTENT_MD5,          "Content-MD5" },
656         { FN_CONTENT_RANGE_DEP,    "Content-Range (encoding 1.1)" },
657         { FN_CONTENT_TYPE,         "Content-Type" },
658         { FN_DATE,                 "Date" },
659         { FN_ETAG,                 "ETag" },
660         { FN_EXPIRES,              "Expires" },
661         { FN_FROM,                 "From" },
662         { FN_HOST,                 "Host" },
663         { FN_IF_MODIFIED_SINCE,    "If-Modified-Since" },
664         { FN_IF_MATCH,             "If-Match" },
665         { FN_IF_NONE_MATCH,        "If-None-Match" },
666         { FN_IF_RANGE,             "If-Range" },
667         { FN_IF_UNMODIFIED_SINCE,  "If-Unmodified-Since" },
668         { FN_LOCATION,             "Location" },
669         { FN_LAST_MODIFIED,        "Last-Modified" },
670         { FN_MAX_FORWARDS,         "Max-Forwards" },
671         { FN_PRAGMA,               "Pragma" },
672         { FN_PROXY_AUTHENTICATE,   "Proxy-Authenticate" },
673         { FN_PROXY_AUTHORIZATION,  "Proxy-Authorization" },
674         { FN_PUBLIC,               "Public" },
675         { FN_RANGE,                "Range" },
676         { FN_REFERER,              "Referer" },
677         { FN_RETRY_AFTER,          "Retry-After" },
678         { FN_SERVER,               "Server" },
679         { FN_TRANSFER_ENCODING,    "Transfer-Encoding" },
680         { FN_UPGRADE,              "Upgrade" },
681         { FN_USER_AGENT,           "User-Agent" },
682         { FN_VARY,                 "Vary" },
683         { FN_VIA,                  "Via" },
684         { FN_WARNING,              "Warning" },
685         { FN_WWW_AUTHENTICATE,     "WWW-Authenticate" },
686         { FN_CONTENT_DISPOSITION,  "Content-Disposition" },
687         { FN_X_WAP_APPLICATION_ID, "X-Wap-Application-ID" },
688         { FN_X_WAP_CONTENT_URI,    "X-Wap-Content-URI" },
689         { FN_X_WAP_INITIATOR_URI,  "X-Wap-Initiator-URI" },
690         { FN_ACCEPT_APPLICATION,   "Accept-Application" },
691         { FN_BEARER_INDICATION,    "Bearer-Indication" },
692         { FN_PUSH_FLAG,            "Push-Flag" },
693         { FN_PROFILE,              "Profile" },
694         { FN_PROFILE_DIFF,         "Profile-Diff" },
695         { FN_PROFILE_WARNING,      "Profile-Warning" },
696         { FN_EXPECT,               "Expect" },
697         { FN_TE,                   "TE" },
698         { FN_TRAILER,              "Trailer" },
699         { FN_ACCEPT_CHARSET,       "Accept-Charset" },
700         { FN_ACCEPT_ENCODING,      "Accept-Encoding" },
701         { FN_CACHE_CONTROL,        "Cache-Control" },
702         { FN_CONTENT_RANGE,        "Content-Range" },
703         { FN_X_WAP_TOD,            "X-Wap-Tod" },
704         { FN_CONTENT_ID,           "Content-ID" },
705         { FN_SET_COOKIE,           "Set-Cookie" },
706         { FN_COOKIE,               "Cookie" },
707         { FN_ENCODING_VERSION,     "Encoding-Version" },
708         { FN_PROFILE_WARNING14,    "Profile-Warning (encoding 1.4)" },
709         { FN_CONTENT_DISPOSITION14,"Content-Disposition (encoding 1.4)" },
710         { FN_X_WAP_SECURITY,       "X-WAP-Security" },
711         { FN_CACHE_CONTROL14,      "Cache-Control (encoding 1.4)" },
712         /* encoding-version 1.5 */
713         { FN_EXPECT15,             "Expect (encoding 1.5)" },
714         { FN_X_WAP_LOC_INVOCATION, "X-Wap-Loc-Invocation" },
715         { FN_X_WAP_LOC_DELIVERY,   "X-Wap-Loc-Delivery" },
716         { 0,                       NULL }
717 };
718
719 /*
720  * Bearer types (from the WDP specification).
721  */
722 #define BT_IPv4                 0x00
723 #define BT_IPv6                 0x01
724 #define BT_GSM_USSD             0x02
725 #define BT_GSM_SMS              0x03
726 #define BT_ANSI_136_GUTS        0x04
727 #define BT_IS_95_SMS            0x05
728 #define BT_IS_95_CSD            0x06
729 #define BT_IS_95_PACKET_DATA    0x07
730 #define BT_ANSI_136_CSD         0x08
731 #define BT_ANSI_136_PACKET_DATA 0x09
732 #define BT_GSM_CSD              0x0A
733 #define BT_GSM_GPRS             0x0B
734 #define BT_GSM_USSD_IPv4        0x0C
735 #define BT_AMPS_CDPD            0x0D
736 #define BT_PDC_CSD              0x0E
737 #define BT_PDC_PACKET_DATA      0x0F
738 #define BT_IDEN_SMS             0x10
739 #define BT_IDEN_CSD             0x11
740 #define BT_IDEN_PACKET_DATA     0x12
741 #define BT_PAGING_FLEX          0x13
742 #define BT_PHS_SMS              0x14
743 #define BT_PHS_CSD              0x15
744 #define BT_GSM_USSD_GSM_SC      0x16
745 #define BT_TETRA_SDS_ITSI       0x17
746 #define BT_TETRA_SDS_MSISDN     0x18
747 #define BT_TETRA_PACKET_DATA    0x19
748 #define BT_PAGING_REFLEX        0x1A
749 #define BT_GSM_USSD_MSISDN      0x1B
750 #define BT_MOBITEX_MPAK         0x1C
751 #define BT_ANSI_136_GHOST       0x1D
752
753 static const value_string vals_bearer_types[] = {
754         { BT_IPv4,                 "IPv4" },
755         { BT_IPv6,                 "IPv6" },
756         { BT_GSM_USSD,             "GSM USSD" },
757         { BT_GSM_SMS,              "GSM SMS" },
758         { BT_ANSI_136_GUTS,        "ANSI-136 GUTS/R-Data" },
759         { BT_IS_95_SMS,            "IS-95 CDMA SMS" },
760         { BT_IS_95_CSD,            "IS-95 CDMA CSD" },
761         { BT_IS_95_PACKET_DATA,    "IS-95 CDMA Packet data" },
762         { BT_ANSI_136_CSD,         "ANSI-136 CSD" },
763         { BT_ANSI_136_PACKET_DATA, "ANSI-136 Packet data" },
764         { BT_GSM_CSD,              "GSM CSD" },
765         { BT_GSM_GPRS,             "GSM GPRS" },
766         { BT_GSM_USSD_IPv4,        "GSM USSD (IPv4 addresses)" },
767         { BT_AMPS_CDPD,            "AMPS CDPD" },
768         { BT_PDC_CSD,              "PDC CSD" },
769         { BT_PDC_PACKET_DATA,      "PDC Packet data" },
770         { BT_IDEN_SMS,             "IDEN SMS" },
771         { BT_IDEN_CSD,             "IDEN CSD" },
772         { BT_IDEN_PACKET_DATA,     "IDEN Packet data" },
773         { BT_PAGING_FLEX,          "Paging network FLEX(TM)" },
774         { BT_PHS_SMS,              "PHS SMS" },
775         { BT_PHS_CSD,              "PHS CSD" },
776         { BT_GSM_USSD_GSM_SC,      "GSM USSD (GSM Service Code addresses)" },
777         { BT_TETRA_SDS_ITSI,       "TETRA SDS (ITSI addresses)" },
778         { BT_TETRA_SDS_MSISDN,     "TETRA SDS (MSISDN addresses)" },
779         { BT_TETRA_PACKET_DATA,    "TETRA Packet data" },
780         { BT_PAGING_REFLEX,        "Paging network ReFLEX(TM)" },
781         { BT_GSM_USSD_MSISDN,      "GSM USSD (MSISDN addresses)" },
782         { BT_MOBITEX_MPAK,         "Mobitex MPAK" },
783         { BT_ANSI_136_GHOST,       "ANSI-136 GHOST/R-Data" },
784         { 0,                       NULL }
785 };
786
787 static const value_string vals_content_types[] = {
788         /* Well-known media types */
789         { 0x00, "*/*" },
790         { 0x01, "text/*" },
791         { 0x02, "text/html" },
792         { 0x03, "text/plain" },
793         { 0x04, "text/x-hdml" },
794         { 0x05, "text/x-ttml" },
795         { 0x06, "text/x-vCalendar" },
796         { 0x07, "text/x-vCard" },
797         { 0x08, "text/vnd.wap.wml" },
798         { 0x09, "text/vnd.wap.wmlscript" },
799         { 0x0A, "text/vnd.wap.channel" },
800         { 0x0B, "multipart/*" },
801         { 0x0C, "multipart/mixed" },
802         { 0x0D, "multipart/form-data" },
803         { 0x0E, "multipart/byteranges" },
804         { 0x0F, "multipart/alternative" },
805         { 0x10, "application/*" },
806         { 0x11, "application/java-vm" },
807         { 0x12, "application/x-www-form-urlencoded" },
808         { 0x13, "application/x-hdmlc" },
809         { 0x14, "application/vnd.wap.wmlc" },
810         { 0x15, "application/vnd.wap.wmlscriptc" },
811         { 0x16, "application/vnd.wap.channelc" },
812         { 0x17, "application/vnd.wap.uaprof" },
813         { 0x18, "application/vnd.wap.wtls-ca-certificate" },
814         { 0x19, "application/vnd.wap.wtls-user-certificate" },
815         { 0x1A, "application/x-x509-ca-cert" },
816         { 0x1B, "application/x-x509-user-cert" },
817         { 0x1C, "image/*" },
818         { 0x1D, "image/gif" },
819         { 0x1E, "image/jpeg" },
820         { 0x1F, "image/tiff" },
821         { 0x20, "image/png" },
822         { 0x21, "image/vnd.wap.wbmp" },
823         { 0x22, "application/vnd.wap.multipart.*" },
824         { 0x23, "application/vnd.wap.multipart.mixed" },
825         { 0x24, "application/vnd.wap.multipart.form-data" },
826         { 0x25, "application/vnd.wap.multipart.byteranges" },
827         { 0x26, "application/vnd.wap.multipart.alternative" },
828         { 0x27, "application/xml" },
829         { 0x28, "text/xml" },
830         { 0x29, "application/vnd.wap.wbxml" },
831         { 0x2A, "application/x-x968-cross-cert" },
832         { 0x2B, "application/x-x968-ca-cert" },
833         { 0x2C, "application/x-x968-user-cert" },
834         { 0x2D, "text/vnd.wap.si" },
835         { 0x2E, "application/vnd.wap.sic" },
836         { 0x2F, "text/vnd.wap.sl" },
837         { 0x30, "application/vnd.wap.slc" },
838         { 0x31, "text/vnd.wap.co" },
839         { 0x32, "application/vnd.wap.coc" },
840         { 0x33, "application/vnd.wap.multipart.related" },
841         { 0x34, "application/vnd.wap.sia" },
842         { 0x35, "text/vnd.wap.connectivity-xml" },
843         { 0x36, "application/vnd.wap.connectivity-wbxml" },
844         { 0x37, "application/pkcs7-mime" },
845         { 0x38, "application/vnd.wap.hashed-certificate" },
846         { 0x39, "application/vnd.wap.signed-certificate" },
847         { 0x3A, "application/vnd.wap.cert-response" },
848         { 0x3B, "application/xhtml+xml" },
849         { 0x3C, "application/wml+xml" },
850         { 0x3D, "text/css" },
851         { 0x3E, "application/vnd.wap.mms-message" },
852         { 0x3F, "application/vnd.wap.rollover-certificate" },
853         { 0x40, "application/vnd.wap.locc+wbxml"},
854         { 0x41, "application/vnd.wap.loc+xml"},
855         { 0x42, "application/vnd.syncml.dm+wbxml"},
856         { 0x43, "application/vnd.syncml.dm+xml"},
857         { 0x44, "application/vnd.syncml.notification"},
858         { 0x45, "application/vnd.wap.xhtml+xml"},
859         { 0x46, "application/vnd.wv.csp.cir"},
860         { 0x47, "application/vnd.oma.dd+xml"},
861         { 0x48, "application/vnd.oma.drm.message"},
862         { 0x49, "application/vnd.oma.drm.content"},
863         { 0x4A, "application/vnd.oma.drm.rights+xml"},
864         { 0x4B, "application/vnd.oma.drm.rights+wbxml"},
865         { 0x4C, "application/vnd.wv.csp+xml"},
866         { 0x4D, "application/vnd.wv.csp+wbxml"},
867         /* The following media types are registered by 3rd parties */ 
868         { 0x0201, "application/vnd.uplanet.cachop-wbxml" },
869         { 0x0202, "application/vnd.uplanet.signal" },
870         { 0x0203, "application/vnd.uplanet.alert-wbxml" },
871         { 0x0204, "application/vnd.uplanet.list-wbxml" },
872         { 0x0205, "application/vnd.uplanet.listcmd-wbxml" },
873         { 0x0206, "application/vnd.uplanet.channel-wbxml" },
874         { 0x0207, "application/vnd.uplanet.provisioning-status-uri" },
875         { 0x0208, "x-wap.multipart/vnd.uplanet.header-set" },
876         { 0x0209, "application/vnd.uplanet.bearer-choice-wbxml" },
877         { 0x020A, "application/vnd.phonecom.mmc-wbxml" },
878         { 0x020B, "application/vnd.nokia.syncset+wbxml" },
879         { 0x020C, "image/x-up-wpng"},
880         { 0x0300, "application/iota.mmc-wbxml"},
881         { 0x0301, "application/iota.mmc-xml"},
882         { 0x00, NULL }
883 };
884
885 static const value_string vals_languages[] = {
886         { 0x01, "Afar (aa)" },
887         { 0x02, "Abkhazian (ab)" },
888         { 0x03, "Afrikaans (af)" },
889         { 0x04, "Amharic (am)" },
890         { 0x05, "Arabic (ar)" },
891         { 0x06, "Assamese (as)" },
892         { 0x07, "Aymara (ay)" },
893         { 0x08, "Azerbaijani (az)" },
894         { 0x09, "Bashkir (ba)" },
895         { 0x0A, "Byelorussian (be)" },
896         { 0x0B, "Bulgarian (bg)" },
897         { 0x0C, "Bihari (bh)" },
898         { 0x0D, "Bislama (bi)" },
899         { 0x0E, "Bengali; Bangla (bn)" },
900         { 0x0F, "Tibetan (bo)" },
901         { 0x10, "Breton (br)" },
902         { 0x11, "Catalan (ca)" },
903         { 0x12, "Corsican (co)" },
904         { 0x13, "Czech (cs)" },
905         { 0x14, "Welsh (cy)" },
906         { 0x15, "Danish (da)" },
907         { 0x16, "German (de)" },
908         { 0x17, "Bhutani (dz)" },
909         { 0x18, "Greek (el)" },
910         { 0x19, "English (en)" },
911         { 0x1A, "Esperanto (eo)" },
912         { 0x1B, "Spanish (es)" },
913         { 0x1C, "Estonian (et)" },
914         { 0x1D, "Basque (eu)" },
915         { 0x1E, "Persian (fa)" },
916         { 0x1F, "Finnish (fi)" },
917         { 0x20, "Fiji (fj)" },
918         { 0x21, "Urdu (ur)" },
919         { 0x22, "French (fr)" },
920         { 0x23, "Uzbek (uz)" },
921         { 0x24, "Irish (ga)" },
922         { 0x25, "Scots Gaelic (gd)" },
923         { 0x26, "Galician (gl)" },
924         { 0x27, "Guarani (gn)" },
925         { 0x28, "Gujarati (gu)" },
926         { 0x29, "Hausa (ha)" },
927         { 0x2A, "Hebrew (formerly iw) (he)" },
928         { 0x2B, "Hindi (hi)" },
929         { 0x2C, "Croatian (hr)" },
930         { 0x2D, "Hungarian (hu)" },
931         { 0x2E, "Armenian (hy)" },
932         { 0x2F, "Vietnamese (vi)" },
933         { 0x30, "Indonesian (formerly in) (id)" },
934         { 0x31, "Wolof (wo)" },
935         { 0x32, "Xhosa (xh)" },
936         { 0x33, "Icelandic (is)" },
937         { 0x34, "Italian (it)" },
938         { 0x35, "Yoruba (yo)" },
939         { 0x36, "Japanese (ja)" },
940         { 0x37, "Javanese (jw)" },
941         { 0x38, "Georgian (ka)" },
942         { 0x39, "Kazakh (kk)" },
943         { 0x3A, "Zhuang (za)" },
944         { 0x3B, "Cambodian (km)" },
945         { 0x3C, "Kannada (kn)" },
946         { 0x3D, "Korean (ko)" },
947         { 0x3E, "Kashmiri (ks)" },
948         { 0x3F, "Kurdish (ku)" },
949         { 0x40, "Kirghiz (ky)" },
950         { 0x41, "Chinese (zh)" },
951         { 0x42, "Lingala (ln)" },
952         { 0x43, "Laothian (lo)" },
953         { 0x44, "Lithuanian (lt)" },
954         { 0x45, "Latvian, Lettish (lv)" },
955         { 0x46, "Malagasy (mg)" },
956         { 0x47, "Maori (mi)" },
957         { 0x48, "Macedonian (mk)" },
958         { 0x49, "Malayalam (ml)" },
959         { 0x4A, "Mongolian (mn)" },
960         { 0x4B, "Moldavian (mo)" },
961         { 0x4C, "Marathi (mr)" },
962         { 0x4D, "Malay (ms)" },
963         { 0x4E, "Maltese (mt)" },
964         { 0x4F, "Burmese (my)" },
965         { 0x50, "Ukrainian (uk)" },
966         { 0x51, "Nepali (ne)" },
967         { 0x52, "Dutch (nl)" },
968         { 0x53, "Norwegian (no)" },
969         { 0x54, "Occitan (oc)" },
970         { 0x55, "(Afan) Oromo (om)" },
971         { 0x56, "Oriya (or)" },
972         { 0x57, "Punjabi (pa)" },
973         { 0x58, "Polish (po)" },
974         { 0x59, "Pashto, Pushto (ps)" },
975         { 0x5A, "Portuguese (pt)" },
976         { 0x5B, "Quechua (qu)" },
977         { 0x5C, "Zulu (zu)" },
978         { 0x5D, "Kirundi (rn)" },
979         { 0x5E, "Romanian (ro)" },
980         { 0x5F, "Russian (ru)" },
981         { 0x60, "Kinyarwanda (rw)" },
982         { 0x61, "Sanskrit (sa)" },
983         { 0x62, "Sindhi (sd)" },
984         { 0x63, "Sangho (sg)" },
985         { 0x64, "Serbo-Croatian (sh)" },
986         { 0x65, "Sinhalese (si)" },
987         { 0x66, "Slovak (sk)" },
988         { 0x67, "Slovenian (sl)" },
989         { 0x68, "Samoan (sm)" },
990         { 0x69, "Shona (sn)" },
991         { 0x6A, "Somali (so)" },
992         { 0x6B, "Albanian (sq)" },
993         { 0x6C, "Serbian (sr)" },
994         { 0x6D, "Siswati (ss)" },
995         { 0x6E, "Sesotho (st)" },
996         { 0x6F, "Sundanese (su)" },
997         { 0x70, "Swedish (sv)" },
998         { 0x71, "Swahili (sw)" },
999         { 0x72, "Tamil (ta)" },
1000         { 0x73, "Telugu (te)" },
1001         { 0x74, "Tajik (tg)" },
1002         { 0x75, "Thai (th)" },
1003         { 0x76, "Tigrinya (ti)" },
1004         { 0x77, "Turkmen (tk)" },
1005         { 0x78, "Tagalog (tl)" },
1006         { 0x79, "Setswana (tn)" },
1007         { 0x7A, "Tonga (to)" },
1008         { 0x7B, "Turkish (tr)" },
1009         { 0x7C, "Tsonga (ts)" },
1010         { 0x7D, "Tatar (tt)" },
1011         { 0x7E, "Twi (tw)" },
1012         { 0x7F, "Uighur (ug)" },
1013         { 0x81, "Nauru (na)" },
1014         { 0x82, "Faeroese (fo)" },
1015         { 0x83, "Frisian (fy)" },
1016         { 0x84, "Interlingua (ia)" },
1017         { 0x85, "Volapuk (vo)" },
1018         { 0x86, "Interlingue (ie)" },
1019         { 0x87, "Inupiak (ik)" },
1020         { 0x88, "Yiddish (formerly ji) (yi)" },
1021         { 0x89, "Inuktitut (iu)" },
1022         { 0x8A, "Greenlandic (kl)" },
1023         { 0x8B, "Latin (la)" },
1024         { 0x8C, "Rhaeto-Romance (rm)" },
1025         { 0x00, NULL }
1026 };
1027
1028
1029 #define CACHE_CONTROL_NO_CACHE                  0x00
1030 #define CACHE_CONTROL_NO_STORE                  0x01
1031 #define CACHE_CONTROL_MAX_AGE                   0x02
1032 #define CACHE_CONTROL_MAX_STALE                 0x03
1033 #define CACHE_CONTROL_MIN_FRESH                 0x04
1034 #define CACHE_CONTROL_ONLY_IF_CACHED    0x05
1035 #define CACHE_CONTROL_PUBLIC                    0x06
1036 #define CACHE_CONTROL_PRIVATE                   0x07
1037 #define CACHE_CONTROL_NO_TRANSFORM              0x08
1038 #define CACHE_CONTROL_MUST_REVALIDATE   0x09
1039 #define CACHE_CONTROL_PROXY_REVALIDATE  0x0A
1040 #define CACHE_CONTROL_S_MAXAGE                  0x0B
1041
1042 static const value_string vals_cache_control[] = {
1043         { CACHE_CONTROL_NO_CACHE,         "no-cache" },
1044         { CACHE_CONTROL_NO_STORE,         "no-store" },
1045         { CACHE_CONTROL_MAX_AGE,          "max-age" },
1046         { CACHE_CONTROL_MAX_STALE,        "max-stale" },
1047         { CACHE_CONTROL_MIN_FRESH,        "min-fresh" },
1048         { CACHE_CONTROL_ONLY_IF_CACHED,   "only-if-cached" },
1049         { CACHE_CONTROL_PUBLIC,           "public" },
1050         { CACHE_CONTROL_PRIVATE,          "private" },
1051         { CACHE_CONTROL_NO_TRANSFORM,     "no-transform" },
1052         { CACHE_CONTROL_MUST_REVALIDATE,  "must-revalidate" },
1053         { CACHE_CONTROL_PROXY_REVALIDATE, "proxy-revalidate" },
1054         { CACHE_CONTROL_S_MAXAGE,         "s-max-age" },
1055
1056         { 0x00, NULL }
1057 };
1058
1059 static const value_string vals_wap_application_ids[] = {
1060         /* Well-known WAP applications */
1061         { 0x00, "x-wap-application:*"},
1062         { 0x01, "x-wap-application:push.sia"},
1063         { 0x02, "x-wap-application:wml.ua"},
1064         { 0x03, "x-wap-application:wta.ua"},
1065         { 0x04, "x-wap-application:mms.ua"},
1066         { 0x05, "x-wap-application:push.syncml"},
1067         { 0x06, "x-wap-application:loc.ua"},
1068         { 0x07, "x-wap-application:syncml.dm"},
1069         { 0x08, "x-wap-application:drm.ua"},
1070         { 0x09, "x-wap-application:emn.ua"},
1071         { 0x0A, "x-wap-application:wv.ua"},
1072         /* Registered by 3rd parties */
1073         { 0x8000, "x-wap-microsoft:localcontent.ua"},
1074         { 0x8001, "x-wap-microsoft:IMclient.ua"},
1075         { 0x8002, "x-wap-docomo:imode.mail.ua"},
1076         { 0x8003, "x-wap-docomo:imode.mr.ua"},
1077         { 0x8004, "x-wap-docomo:imode.mf.ua"},
1078         { 0x8005, "x-motorola:location.ua"},
1079         { 0x8006, "x-motorola:now.ua"},
1080         { 0x8007, "x-motorola:otaprov.ua"},
1081         { 0x8008, "x-motorola:browser.ua"},
1082         { 0x8009, "x-motorola:splash.ua"},
1083         /* 0x800A: unassigned */
1084         { 0x800B, "x-wap-nai:mvsw.command"},
1085         /* 0x800C -- 0x800F: unassigned */
1086         { 0x8010, "x-wap-openwave:iota.ua"},
1087         /* 0x8011 -- 0x8FFF: unassigned */
1088         { 0x9000, "x-wap-docomo:imode.mail2.ua"},
1089         { 0x9001, "x-oma-nec:otaprov.ua"},
1090         { 0x9002, "x-oma-nokia:call.ua"},
1091         { 0x9003, "x-oma-coremobility:sqa.ua"},
1092
1093         { 0x00, NULL }
1094 };
1095
1096
1097 /* Parameters and well-known encodings */
1098 static const value_string vals_wsp_parameter_sec[] = {
1099         { 0x00, "NETWPIN" },
1100         { 0x01, "USERPIN" },
1101         { 0x02, "USERNETWPIN" },
1102         { 0x03, "USERPINMAC" },
1103
1104         { 0x00, NULL }
1105 };
1106
1107 /* Warning codes and mappings */
1108 static const value_string vals_wsp_warning_code[] = {
1109         { 10, "110 Response is stale" },
1110         { 11, "111 Revalidation failed" },
1111         { 12, "112 Disconnected operation" },
1112         { 13, "113 Heuristic expiration" },
1113         { 14, "214 Transformation applied" },
1114         { 99, "199/299 Miscellaneous warning" },
1115
1116         { 0, NULL }
1117 };
1118
1119 static const value_string vals_wsp_warning_code_short[] = {
1120         { 10, "110" },
1121         { 11, "111" },
1122         { 12, "112" },
1123         { 13, "113" },
1124         { 14, "214" },
1125         { 99, "199/299" },
1126
1127         { 0, NULL }
1128 };
1129
1130 /* Profile-Warning codes - see http://www.w3.org/TR/NOTE-CCPPexchange */
1131 static const value_string vals_wsp_profile_warning_code[] = {
1132         { 0x10, "100 OK" },
1133         { 0x11, "101 Used stale profile" },
1134         { 0x12, "102 Not used profile" },
1135         { 0x20, "200 Not applied" },
1136         { 0x21, "101 Content selection applied" },
1137         { 0x22, "202 Content generation applied" },
1138         { 0x23, "203 Transformation applied" },
1139
1140         { 0x00, NULL }
1141 };
1142
1143 /* Well-known TE values */
1144 static const value_string vals_well_known_te[] = {
1145         { 0x82, "chunked" },
1146         { 0x83, "identity" },
1147         { 0x84, "gzip" },
1148         { 0x85, "compress" },
1149         { 0x86, "deflate" },
1150
1151         { 0x00, NULL }
1152 };
1153
1154
1155 /*
1156  * Redirect flags.
1157  */
1158 #define PERMANENT_REDIRECT              0x80
1159 #define REUSE_SECURITY_SESSION  0x40
1160
1161 /*
1162  * Redirect address flags and length.
1163  */
1164 #define BEARER_TYPE_INCLUDED    0x80
1165 #define PORT_NUMBER_INCLUDED    0x40
1166 #define ADDRESS_LEN                             0x3f
1167
1168 static const true_false_string yes_no_truth = {
1169         "Yes" ,
1170         "No"
1171 };
1172
1173 static const value_string vals_false_true[] = {
1174         { 0, "False" },
1175         { 1, "True" },
1176         { 0, NULL },
1177 };
1178
1179 enum {
1180         WSP_PDU_RESERVED                = 0x00,
1181         WSP_PDU_CONNECT                 = 0x01,
1182         WSP_PDU_CONNECTREPLY            = 0x02,
1183         WSP_PDU_REDIRECT                = 0x03,                 /* No sample data */
1184         WSP_PDU_REPLY                   = 0x04,
1185         WSP_PDU_DISCONNECT              = 0x05,
1186         WSP_PDU_PUSH                    = 0x06,                 /* No sample data */
1187         WSP_PDU_CONFIRMEDPUSH           = 0x07,                 /* No sample data */
1188         WSP_PDU_SUSPEND                 = 0x08,                 /* No sample data */
1189         WSP_PDU_RESUME                  = 0x09,                 /* No sample data */
1190
1191         WSP_PDU_GET                     = 0x40,
1192         WSP_PDU_OPTIONS                 = 0x41,                 /* No sample data */
1193         WSP_PDU_HEAD                    = 0x42,                 /* No sample data */
1194         WSP_PDU_DELETE                  = 0x43,                 /* No sample data */
1195         WSP_PDU_TRACE                   = 0x44,                 /* No sample data */
1196
1197         WSP_PDU_POST                    = 0x60,
1198         WSP_PDU_PUT                     = 0x61                  /* No sample data */
1199 };
1200
1201
1202 /* Dissector tables for handoff */
1203 static dissector_table_t media_type_table;
1204 static heur_dissector_list_t heur_subdissector_list;
1205
1206 static void add_uri (proto_tree *, packet_info *, tvbuff_t *, guint, guint);
1207
1208 static void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
1209 static void add_multipart_data (proto_tree *, tvbuff_t *);
1210
1211 static void add_capabilities (proto_tree *tree, tvbuff_t *tvb, guint8 pdu_type);
1212
1213
1214 /*
1215  * Dissect the WSP header part.
1216  * This function calls wkh_XXX functions that dissect well-known headers.
1217  */
1218 static void add_headers (proto_tree *tree, tvbuff_t *tvb, int hf);
1219
1220 /* The following macros define WSP basic data structures as found
1221  * in the ABNF notation of WSP headers.
1222  * Currently all text data types are mapped to text_string.
1223  */
1224 #define is_short_integer(x)             ( (x) & 0x80 )
1225 #define is_long_integer(x)              ( (x) <= 30 )
1226 #define is_date_value(x)                is_long_integer(x)
1227 #define is_integer_value(x)             (is_short_integer(x) || is_long_integer(x))
1228 #define is_delta_seconds_value(x)       is_integer_value(x)
1229 /* Text string == *TEXT 0x00, thus also an empty string matches the rule! */
1230 #define is_text_string(x)       ( ((x) == 0) || ( ((x) >= 32) && ((x) <= 127)) ) 
1231 #define is_quoted_string(x)             ( (x) == 0x22 ) /* " */
1232 #define is_token_text(x)                is_text_string(x)
1233 #define is_text_value(x)                is_text_string(x)
1234 #define is_uri_value(x)                 is_text_string(x)
1235
1236 #define get_uintvar_integer(val,tvb,start,len,ok) \
1237         val = tvb_get_guintvar(tvb,start,&len); \
1238         if (len>5) ok = FALSE; else ok = TRUE;
1239 #define get_short_integer(val,tvb,start,len,ok) \
1240         val = tvb_get_guint8(tvb,start); \
1241         if (val & 0x80) ok = TRUE; else ok=FALSE; \
1242         val &= 0x7F; len = 1;
1243 #define get_long_integer(val,tvb,start,len,ok) \
1244         len = tvb_get_guint8(tvb,start); \
1245         ok = TRUE; /* Valid lengths for us are 1-4 */ \
1246         if (len==1) { val = tvb_get_guint8(tvb,start+1); } \
1247         else if (len==2) { val = tvb_get_ntohs(tvb,start+1); } \
1248         else if (len==3) { val = tvb_get_ntoh24(tvb,start+1); } \
1249         else if (len==4) { val = tvb_get_ntohl(tvb,start+1); } \
1250         else ok = FALSE; \
1251         len++; /* Add the 1st octet to the length */
1252 #define get_integer_value(val,tvb,start,len,ok) \
1253         len = tvb_get_guint8(tvb,start); \
1254         ok = TRUE; \
1255         if (len & 0x80) { val = len & 0x7F; len = 0; } \
1256         else if (len==1) { val = tvb_get_guint8(tvb,start+1); } \
1257         else if (len==2) { val = tvb_get_ntohs(tvb,start+1); } \
1258         else if (len==3) { val = tvb_get_ntoh24(tvb,start+1); } \
1259         else if (len==4) { val = tvb_get_ntohl(tvb,start+1); } \
1260         else ok = FALSE; \
1261         len++; /* Add the 1st octet to the length */
1262 #define get_date_value(val,tvb,start,len,ok) \
1263         get_long_integer(val,tvb,start,len,ok)
1264 #define get_delta_seconds_value(val,tvb,start,len,ok) \
1265         get_integer_value(val,tvb,start,len,ok)
1266
1267 /* NOTE - Don't forget to g_free() the str value after its usage as the
1268  * tvb_get_string[z]() functions return g_malloc()ed memory! */ 
1269 #define get_text_string(str,tvb,start,len,ok) \
1270         if (is_text_string(tvb_get_guint8(tvb,start))) { \
1271                 str = tvb_get_stringz(tvb,start,&len); \
1272                 g_assert (str); \
1273                 ok = TRUE; \
1274         } else { len = 0; str = NULL; ok = FALSE; }
1275 #define get_token_text(str,tvb,start,len,ok) \
1276         get_text_string(str,tvb,start,len,ok)
1277 #define get_extension_media(str,tvb,start,len,ok) \
1278         get_text_string(str,tvb,start,len,ok)
1279 #define get_text_value(str,tvb,start,len,ok) \
1280         get_text_string(str,tvb,start,len,ok)
1281 #define get_quoted_string(str,tvb,start,len,ok) \
1282         get_text_string(str,tvb,start,len,ok)
1283 #define get_uri_value(str,tvb,start,len,ok) \
1284         get_text_string(str,tvb,start,len,ok)
1285
1286 #define get_version_value(val,str,tvb,start,len,ok) \
1287         val = tvb_get_guint8(tvb,start); \
1288         ok = TRUE; \
1289         if (val & 0x80) { /* High nibble "." Low nibble */ \
1290                 len = 1; \
1291                 val &= 0x7F; \
1292                 str = g_strdup_printf("%u.%u", val >> 4, val & 0x0F); \
1293         } else { get_text_string(str,tvb,start,len,ok); }
1294         
1295 /* Parameter parser */
1296 static int
1297 parameter (proto_tree *tree, proto_item *ti, tvbuff_t *tvb, int start, int len);
1298 static int
1299 parameter_value_q (proto_tree *tree, proto_item *ti, tvbuff_t *tvb, int start);
1300
1301 #define InvalidValueForHeader(hdr) \
1302         "<Error: Invalid value for the '" hdr "' header>"
1303 #define InvalidTextualHeader \
1304         "<Error: Invalid zero-length textual header>"
1305 #define TrailingQuoteWarning \
1306         " <Warning: Quoted-string value has been encoded with a trailing quote>"
1307
1308 /* WSP well-known header parsing function prototypes;
1309  * will be listed in the function lookup table WellKnownHeaders[] */
1310 static guint32 wkh_default (proto_tree *tree, tvbuff_t *tvb,
1311                 guint32 hdr_start);
1312 static guint32 wkh_accept (proto_tree *tree, tvbuff_t *tvb,
1313                 guint32 hdr_start);
1314 static guint32 wkh_content_type (proto_tree *tree, tvbuff_t *tvb,
1315                 guint32 hdr_start);
1316 static guint32 wkh_accept_charset (proto_tree *tree, tvbuff_t *tvb,
1317                 guint32 hdr_start);
1318 static guint32 wkh_accept_language (proto_tree *tree, tvbuff_t *tvb,
1319                 guint32 hdr_start);
1320 static guint32 wkh_connection (proto_tree *tree, tvbuff_t *tvb,
1321                 guint32 hdr_start);
1322 static guint32 wkh_push_flag (proto_tree *tree, tvbuff_t *tvb,
1323                 guint32 header_start);
1324 static guint32 wkh_vary (proto_tree *tree, tvbuff_t *tvb,
1325                 guint32 hdr_start);
1326 static guint32 wkh_accept_ranges (proto_tree *tree, tvbuff_t *tvb,
1327                 guint32 hdr_start);
1328 static guint32 wkh_content_disposition (proto_tree *tree, tvbuff_t *tvb,
1329                 guint32 hdr_start);
1330 static guint32 wkh_accept_encoding (proto_tree *tree, tvbuff_t *tvb,
1331                 guint32 hdr_start);
1332 static guint32 wkh_content_encoding (proto_tree *tree, tvbuff_t *tvb,
1333                 guint32 hdr_start);
1334 static guint32 wkh_transfer_encoding (proto_tree *tree, tvbuff_t *tvb,
1335                 guint32 hdr_start);
1336 static guint32 wkh_pragma (proto_tree *tree, tvbuff_t *tvb,
1337                 guint32 hdr_start);
1338 /* Single short-integer value */
1339 static guint32 wkh_x_wap_security (proto_tree *tree, tvbuff_t *tvb,
1340                 guint32 hdr_start);
1341 /* Text */
1342 static guint32 wkh_content_base (proto_tree *tree, tvbuff_t *tvb,
1343                 guint32 hdr_start);
1344 static guint32 wkh_content_location (proto_tree *tree, tvbuff_t *tvb,
1345                 guint32 hdr_start);
1346 static guint32 wkh_etag (proto_tree *tree, tvbuff_t *tvb,
1347                 guint32 hdr_start);
1348 static guint32 wkh_from (proto_tree *tree, tvbuff_t *tvb,
1349                 guint32 hdr_start);
1350 static guint32 wkh_host (proto_tree *tree, tvbuff_t *tvb,
1351                 guint32 hdr_start);
1352 static guint32 wkh_if_match (proto_tree *tree, tvbuff_t *tvb,
1353                 guint32 hdr_start);
1354 static guint32 wkh_if_none_match (proto_tree *tree, tvbuff_t *tvb,
1355                 guint32 hdr_start);
1356 static guint32 wkh_location (proto_tree *tree, tvbuff_t *tvb,
1357                 guint32 hdr_start);
1358 static guint32 wkh_referer (proto_tree *tree, tvbuff_t *tvb,
1359                 guint32 hdr_start);
1360 static guint32 wkh_server (proto_tree *tree, tvbuff_t *tvb,
1361                 guint32 hdr_start);
1362 static guint32 wkh_user_agent (proto_tree *tree, tvbuff_t *tvb,
1363                 guint32 hdr_start);
1364 static guint32 wkh_upgrade (proto_tree *tree, tvbuff_t *tvb,
1365                 guint32 hdr_start);
1366 static guint32 wkh_via (proto_tree *tree, tvbuff_t *tvb,
1367                 guint32 hdr_start);
1368 static guint32 wkh_content_uri (proto_tree *tree, tvbuff_t *tvb,
1369                 guint32 hdr_start);
1370 static guint32 wkh_initiator_uri (proto_tree *tree, tvbuff_t *tvb,
1371                 guint32 hdr_start);
1372 static guint32 wkh_profile (proto_tree *tree, tvbuff_t *tvb,
1373                 guint32 hdr_start);
1374 static guint32 wkh_content_id (proto_tree *tree, tvbuff_t *tvb,
1375                 guint32 hdr_start);
1376 /* Date-value or text */
1377 static guint32 wkh_if_range (proto_tree *tree, tvbuff_t *tvb,
1378                 guint32 hdr_start);
1379 /* Date-value */
1380 static guint32 wkh_date (proto_tree *tree, tvbuff_t *tvb,
1381                 guint32 hdr_start);
1382 static guint32 wkh_expires (proto_tree *tree, tvbuff_t *tvb,
1383                 guint32 hdr_start);
1384 static guint32 wkh_if_modified_since (proto_tree *tree, tvbuff_t *tvb,
1385                 guint32 hdr_start);
1386 static guint32 wkh_if_unmodified_since (proto_tree *tree, tvbuff_t *tvb,
1387                 guint32 hdr_start);
1388 static guint32 wkh_last_modified (proto_tree *tree, tvbuff_t *tvb,
1389                 guint32 hdr_start);
1390 /* Date-value with special meaning */
1391 static guint32 wkh_x_wap_tod (proto_tree *tree, tvbuff_t *tvb,
1392                 guint32 hdr_start);
1393 /* Delta-seconds-value */
1394 static guint32 wkh_age (proto_tree *tree, tvbuff_t *tvb,
1395                 guint32 hdr_start);
1396 /* Challenge */
1397 static guint32 wkh_proxy_authenticate (proto_tree *tree, tvbuff_t *tvb,
1398                 guint32 hdr_start);
1399 static guint32 wkh_www_authenticate (proto_tree *tree, tvbuff_t *tvb,
1400                 guint32 hdr_start);
1401 /* Credentials */
1402 static guint32 wkh_authorization (proto_tree *tree, tvbuff_t *tvb,
1403                 guint32 hdr_start);
1404 static guint32 wkh_proxy_authorization (proto_tree *tree, tvbuff_t *tvb,
1405                 guint32 hdr_start);
1406 /* Pragma */
1407 static guint32 wkh_pragma (proto_tree *tree, tvbuff_t *tvb,
1408                 guint32 hdr_start);
1409 /* Integer-value */
1410 static guint32 wkh_content_length (proto_tree *tree, tvbuff_t *tvb,
1411                 guint32 hdr_start);
1412 static guint32 wkh_max_forwards (proto_tree *tree, tvbuff_t *tvb,
1413                 guint32 hdr_start);
1414
1415 /* Integer lookup value */
1416 static guint32 wkh_bearer_indication (proto_tree *tree, tvbuff_t *tvb,
1417                 guint32 hdr_start);
1418
1419 /* WAP application ID value */
1420 static guint32 wkh_x_wap_application_id (proto_tree *tree, tvbuff_t *tvb,
1421                 guint32 hdr_start);
1422 static guint32 wkh_accept_application (proto_tree *tree, tvbuff_t *tvb,
1423                 guint32 hdr_start);
1424 static guint32 wkh_content_language (proto_tree *tree, tvbuff_t *tvb,
1425                 guint32 hdr_start);
1426
1427 /* Allow and Public */
1428 static guint32 wkh_allow(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start);
1429 static guint32 wkh_public(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start);
1430
1431 /* Cache-control */
1432 static guint32 wkh_cache_control (proto_tree *tree, tvbuff_t *tvb,
1433                 guint32 hdr_start);
1434 /* Warning */
1435 static guint32 wkh_warning (proto_tree *tree, tvbuff_t *tvb,
1436                 guint32 hdr_start);
1437 /* Profile-warning */
1438 static guint32 wkh_profile_warning (proto_tree *tree, tvbuff_t *tvb,
1439                 guint32 hdr_start);
1440
1441 /* Content-MD5 */
1442 static guint32 wkh_content_md5 (proto_tree *tree, tvbuff_t *tvb,
1443                 guint32 hdr_start);
1444
1445 /* WSP encoding version */
1446 static guint32 wkh_encoding_version (proto_tree *tree, tvbuff_t *tvb,
1447                 guint32 hdr_start);
1448
1449 /* Content-Range and Range */
1450 static guint32 wkh_content_range (proto_tree *tree, tvbuff_t *tvb,
1451                 guint32 hdr_start);
1452 static guint32 wkh_range (proto_tree *tree, tvbuff_t *tvb,
1453                 guint32 hdr_start);
1454
1455 /* TE */
1456 static guint32 wkh_te (proto_tree *tree, tvbuff_t *tvb,
1457                 guint32 hdr_start);
1458
1459 /* Header value */
1460 static guint32 wkh_trailer (proto_tree *tree, tvbuff_t *tvb,
1461                 guint32 hdr_start);
1462
1463 /* TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
1464 static guint32 wkh_retry_after (proto_tree *tree, tvbuff_t *tvb,
1465                 guint32 hdr_start);
1466 static guint32 wkh_profile_diff (proto_tree *tree, tvbuff_t *tvb,
1467                 guint32 hdr_start);
1468 static guint32 wkh_expect (proto_tree *tree, tvbuff_t *tvb,
1469                 guint32 hdr_start);
1470 static guint32 wkh_set_cookie (proto_tree *tree, tvbuff_t *tvb,
1471                 guint32 hdr_start);
1472 static guint32 wkh_cookie (proto_tree *tree, tvbuff_t *tvb,
1473                 guint32 hdr_start);
1474 */
1475
1476
1477 /* WSP well-known Openwave header parsing function prototypes;
1478  * will be listed in the function lookup table WellKnownOpenwaveHeaders[] */
1479 static guint32 wkh_openwave_default (proto_tree *tree, tvbuff_t *tvb,
1480                 guint32 hdr_start);
1481 /* Textual headers */
1482 static guint32 wkh_openwave_x_up_proxy_operator_domain(proto_tree *tree,
1483                 tvbuff_t *tvb, guint32 hdr_start);
1484 static guint32 wkh_openwave_x_up_proxy_home_page(proto_tree *tree,
1485                 tvbuff_t *tvb, guint32 hdr_start);
1486 static guint32 wkh_openwave_x_up_proxy_uplink_version(proto_tree *tree,
1487                 tvbuff_t *tvb, guint32 hdr_start);
1488 static guint32 wkh_openwave_x_up_proxy_ba_realm(proto_tree *tree,
1489                 tvbuff_t *tvb, guint32 hdr_start);
1490 static guint32 wkh_openwave_x_up_proxy_request_uri(proto_tree *tree,
1491                 tvbuff_t *tvb, guint32 hdr_start);
1492 static guint32 wkh_openwave_x_up_proxy_bookmark(proto_tree *tree,
1493                 tvbuff_t *tvb, guint32 hdr_start);
1494 /* Integer headers */
1495 static guint32 wkh_openwave_x_up_proxy_push_seq(proto_tree *tree,
1496                 tvbuff_t *tvb, guint32 hdr_start);
1497 static guint32 wkh_openwave_x_up_proxy_notify(proto_tree *tree,
1498                 tvbuff_t *tvb, guint32 hdr_start);
1499 static guint32 wkh_openwave_x_up_proxy_net_ask(proto_tree *tree,
1500                 tvbuff_t *tvb, guint32 hdr_start);
1501 static guint32 wkh_openwave_x_up_proxy_tod (proto_tree *tree,
1502                 tvbuff_t *tvb, guint32 hdr_start);
1503 static guint32 wkh_openwave_x_up_proxy_ba_enable(proto_tree *tree,
1504                 tvbuff_t *tvb, guint32 hdr_start);
1505 static guint32 wkh_openwave_x_up_proxy_redirect_enable(proto_tree *tree,
1506                 tvbuff_t *tvb, guint32 hdr_start);
1507 static guint32 wkh_openwave_x_up_proxy_redirect_status(proto_tree *tree,
1508                 tvbuff_t *tvb, guint32 hdr_start);
1509 static guint32 wkh_openwave_x_up_proxy_linger(proto_tree *tree,
1510                 tvbuff_t *tvb, guint32 hdr_start);
1511 static guint32 wkh_openwave_x_up_proxy_enable_trust(proto_tree *tree,
1512                 tvbuff_t *tvb, guint32 hdr_start);
1513 static guint32 wkh_openwave_x_up_proxy_trust(proto_tree *tree,
1514                 tvbuff_t *tvb, guint32 hdr_start);
1515 static guint32 wkh_openwave_x_up_devcap_has_color(proto_tree *tree,
1516                 tvbuff_t *tvb, guint32 hdr_start);
1517 static guint32 wkh_openwave_x_up_devcap_num_softkeys(proto_tree *tree,
1518                 tvbuff_t *tvb, guint32 hdr_start);
1519 static guint32 wkh_openwave_x_up_devcap_softkey_size(proto_tree *tree,
1520                 tvbuff_t *tvb, guint32 hdr_start);
1521 static guint32 wkh_openwave_x_up_devcap_screen_chars(proto_tree *tree,
1522                 tvbuff_t *tvb, guint32 hdr_start);
1523 static guint32 wkh_openwave_x_up_devcap_screen_pixels(proto_tree *tree,
1524                 tvbuff_t *tvb, guint32 hdr_start);
1525 static guint32 wkh_openwave_x_up_devcap_em_size(proto_tree *tree,
1526                 tvbuff_t *tvb, guint32 hdr_start);
1527 static guint32 wkh_openwave_x_up_devcap_screen_depth(proto_tree *tree,
1528                 tvbuff_t *tvb, guint32 hdr_start);
1529 static guint32 wkh_openwave_x_up_devcap_immed_alert(proto_tree *tree,
1530                 tvbuff_t *tvb, guint32 hdr_start);
1531 static guint32 wkh_openwave_x_up_devcap_gui(proto_tree *tree,
1532                 tvbuff_t *tvb, guint32 hdr_start);
1533
1534 static guint32 wkh_openwave_x_up_proxy_trans_charset(proto_tree *tree,
1535                 tvbuff_t *tvb, guint32 hdr_start);
1536 static guint32 wkh_openwave_x_up_proxy_push_accept(proto_tree *tree,
1537                 tvbuff_t *tvb, guint32 hdr_start);
1538
1539
1540 /* Define a pointer to function data type for the well-known header
1541  * lookup table below */
1542 typedef guint32 (*hdr_parse_func_ptr) (proto_tree *, tvbuff_t *, guint32);
1543
1544 /* Lookup table for well-known header parsing functions */
1545 static const hdr_parse_func_ptr WellKnownHeader[128] = {
1546         /* 0x00 */      wkh_accept,                             /* 0x01 */      wkh_accept_charset,
1547         /* 0x02 */      wkh_accept_encoding,    /* 0x03 */      wkh_accept_language,
1548         /* 0x04 */      wkh_accept_ranges,              /* 0x05 */      wkh_age,
1549         /* 0x06 */      wkh_allow,                              /* 0x07 */      wkh_authorization,
1550         /* 0x08 */      wkh_cache_control,              /* 0x09 */      wkh_connection,
1551         /* 0x0A */      wkh_content_base,               /* 0x0B */      wkh_content_encoding,
1552         /* 0x0C */      wkh_content_language,   /* 0x0D */      wkh_content_length,
1553         /* 0x0E */      wkh_content_location,   /* 0x0F */      wkh_content_md5,
1554         /* 0x10 */      wkh_content_range,              /* 0x11 */      wkh_content_type,
1555         /* 0x12 */      wkh_date,                               /* 0x13 */      wkh_etag,
1556         /* 0x14 */      wkh_expires,                    /* 0x15 */      wkh_from,
1557         /* 0x16 */      wkh_host,                               /* 0x17 */      wkh_if_modified_since,
1558         /* 0x18 */      wkh_if_match,                   /* 0x19 */      wkh_if_none_match,
1559         /* 0x1A */      wkh_if_range,                   /* 0x1B */      wkh_if_unmodified_since,
1560         /* 0x1C */      wkh_location,                   /* 0x1D */      wkh_last_modified,
1561         /* 0x1E */      wkh_max_forwards,               /* 0x1F */      wkh_pragma,
1562         /* 0x20 */      wkh_proxy_authenticate, /* 0x21 */      wkh_proxy_authorization,
1563         /* 0x22 */      wkh_public,                             /* 0x23 */      wkh_range,
1564         /* 0x24 */      wkh_referer,                    /* 0x25 */      wkh_default,
1565         /* 0x26 */      wkh_server,                             /* 0x27 */      wkh_transfer_encoding,
1566         /* 0x28 */      wkh_upgrade,                    /* 0x29 */      wkh_user_agent,
1567         /* 0x2A */      wkh_vary,                               /* 0x2B */      wkh_via,
1568         /* 0x2C */      wkh_warning,                    /* 0x2D */      wkh_www_authenticate,
1569         /* 0x2E */      wkh_content_disposition,/* 0x2F */      wkh_x_wap_application_id,
1570         /* 0x30 */      wkh_content_uri,                /* 0x31 */      wkh_initiator_uri,
1571         /* 0x32 */      wkh_accept_application, /* 0x33 */      wkh_bearer_indication,
1572         /* 0x34 */      wkh_push_flag,                  /* 0x35 */      wkh_profile,
1573         /* 0x36 */      wkh_default,                    /* 0x37 */      wkh_profile_warning,
1574         /* 0x38 */      wkh_default,                    /* 0x39 */      wkh_te,
1575         /* 0x3A */      wkh_trailer,                    /* 0x3B */      wkh_accept_charset,
1576         /* 0x3C */      wkh_accept_encoding,    /* 0x3D */      wkh_cache_control,
1577         /* 0x3E */      wkh_content_range,              /* 0x3F */      wkh_x_wap_tod,
1578         /* 0x40 */      wkh_content_id,                 /* 0x41 */      wkh_default,
1579         /* 0x42 */      wkh_default,                    /* 0x43 */      wkh_encoding_version,
1580         /* 0x44 */      wkh_profile_warning,    /* 0x45 */      wkh_content_disposition,
1581         /* 0x46 */      wkh_x_wap_security,             /* 0x47 */      wkh_cache_control,
1582         /*******************************************************
1583          *** The following headers are not (yet) registered. ***
1584          *******************************************************/
1585         /* 0x48 */      wkh_default,                    /* 0x49 */      wkh_default,
1586         /* 0x4A */      wkh_default,                    /* 0x4B */      wkh_default,
1587         /* 0x4C */      wkh_default,                    /* 0x4D */      wkh_default,
1588         /* 0x4E */      wkh_default,                    /* 0x4F */      wkh_default,
1589         /* 0x50 */      wkh_default,                    /* 0x51 */      wkh_default,
1590         /* 0x52 */      wkh_default,                    /* 0x53 */      wkh_default,
1591         /* 0x54 */      wkh_default,                    /* 0x55 */      wkh_default,
1592         /* 0x56 */      wkh_default,                    /* 0x57 */      wkh_default,
1593         /* 0x58 */      wkh_default,                    /* 0x59 */      wkh_default,
1594         /* 0x5A */      wkh_default,                    /* 0x5B */      wkh_default,
1595         /* 0x5C */      wkh_default,                    /* 0x5D */      wkh_default,
1596         /* 0x5E */      wkh_default,                    /* 0x5F */      wkh_default,
1597         /* 0x60 */      wkh_default,                    /* 0x61 */      wkh_default,
1598         /* 0x62 */      wkh_default,                    /* 0x63 */      wkh_default,
1599         /* 0x64 */      wkh_default,                    /* 0x65 */      wkh_default,
1600         /* 0x66 */      wkh_default,                    /* 0x67 */      wkh_default,
1601         /* 0x68 */      wkh_default,                    /* 0x69 */      wkh_default,
1602         /* 0x6A */      wkh_default,                    /* 0x6B */      wkh_default,
1603         /* 0x6C */      wkh_default,                    /* 0x6D */      wkh_default,
1604         /* 0x6E */      wkh_default,                    /* 0x6F */      wkh_default,
1605         /* 0x70 */      wkh_default,                    /* 0x71 */      wkh_default,
1606         /* 0x72 */      wkh_default,                    /* 0x73 */      wkh_default,
1607         /* 0x74 */      wkh_default,                    /* 0x75 */      wkh_default,
1608         /* 0x76 */      wkh_default,                    /* 0x77 */      wkh_default,
1609         /* 0x78 */      wkh_default,                    /* 0x79 */      wkh_default,
1610         /* 0x7A */      wkh_default,                    /* 0x7B */      wkh_default,
1611         /* 0x7C */      wkh_default,                    /* 0x7D */      wkh_default,
1612         /* 0x7E */      wkh_default,                    /* 0x7F */      wkh_default,
1613 }; 
1614
1615 /* Lookup table for well-known header parsing functions */
1616 static const hdr_parse_func_ptr WellKnownOpenwaveHeader[128] = {
1617         /* 0x00 */      wkh_openwave_default,
1618         /* 0x01 */      wkh_openwave_x_up_proxy_push_accept,
1619         /* 0x02 */      wkh_openwave_x_up_proxy_push_seq,
1620         /* 0x03 */      wkh_openwave_x_up_proxy_notify,
1621         /* 0x04 */      wkh_openwave_x_up_proxy_operator_domain,
1622         /* 0x05 */      wkh_openwave_x_up_proxy_home_page,
1623         /* 0x06 */      wkh_openwave_x_up_devcap_has_color,
1624         /* 0x07 */      wkh_openwave_x_up_devcap_num_softkeys,
1625         /* 0x08 */      wkh_openwave_x_up_devcap_softkey_size,
1626         /* 0x09 */      wkh_openwave_x_up_devcap_screen_chars,
1627         /* 0x0A */      wkh_openwave_x_up_devcap_screen_pixels,
1628         /* 0x0B */      wkh_openwave_x_up_devcap_em_size,
1629         /* 0x0C */      wkh_openwave_x_up_devcap_screen_depth,
1630         /* 0x0D */      wkh_openwave_x_up_devcap_immed_alert,
1631         /* 0x0E */      wkh_openwave_x_up_proxy_net_ask,
1632         /* 0x0F */      wkh_openwave_x_up_proxy_uplink_version,
1633         /* 0x10 */      wkh_openwave_x_up_proxy_tod,
1634         /* 0x11 */      wkh_openwave_x_up_proxy_ba_enable,
1635         /* 0x12 */      wkh_openwave_x_up_proxy_ba_realm,
1636         /* 0x13 */      wkh_openwave_x_up_proxy_redirect_enable,
1637         /* 0x14 */      wkh_openwave_x_up_proxy_request_uri,
1638         /* 0x15 */      wkh_openwave_x_up_proxy_redirect_status,
1639         /* 0x16 */      wkh_openwave_x_up_proxy_trans_charset,
1640         /* 0x17 */      wkh_openwave_x_up_proxy_linger,
1641         /* 0x18 */      wkh_openwave_default,
1642         /* 0x19 */      wkh_openwave_x_up_proxy_enable_trust,
1643         /* 0x1A */      wkh_openwave_x_up_proxy_trust,
1644         /* 0x1B */      wkh_openwave_default,
1645         /* 0x1C */      wkh_openwave_default,
1646         /* 0x1D */      wkh_openwave_default,
1647         /* 0x1E */      wkh_openwave_default,
1648         /* 0x1F */      wkh_openwave_default,
1649         /* 0x20 */      wkh_openwave_x_up_proxy_trust,
1650         /* 0x21 */      wkh_openwave_x_up_proxy_bookmark,
1651         /* 0x22 */      wkh_openwave_x_up_devcap_gui,
1652         /*******************************************************
1653          *** The following headers are not (yet) registered. ***
1654          *******************************************************/
1655         /* 0x23 */      wkh_openwave_default,
1656         /* 0x24 */      wkh_openwave_default,           /* 0x25 */      wkh_openwave_default,
1657         /* 0x26 */      wkh_openwave_default,           /* 0x27 */      wkh_openwave_default,
1658         /* 0x28 */      wkh_openwave_default,           /* 0x29 */      wkh_openwave_default,
1659         /* 0x2A */      wkh_openwave_default,           /* 0x2B */      wkh_openwave_default,
1660         /* 0x2C */      wkh_openwave_default,           /* 0x2D */      wkh_openwave_default,
1661         /* 0x2E */      wkh_openwave_default,           /* 0x2F */      wkh_openwave_default,
1662         /* 0x30 */      wkh_openwave_default,           /* 0x31 */      wkh_openwave_default,
1663         /* 0x32 */      wkh_openwave_default,           /* 0x33 */      wkh_openwave_default,
1664         /* 0x34 */      wkh_openwave_default,           /* 0x35 */      wkh_openwave_default,
1665         /* 0x36 */      wkh_openwave_default,           /* 0x37 */      wkh_openwave_default,
1666         /* 0x38 */      wkh_openwave_default,           /* 0x39 */      wkh_openwave_default,
1667         /* 0x3A */      wkh_openwave_default,           /* 0x3B */      wkh_openwave_default,
1668         /* 0x3C */      wkh_openwave_default,           /* 0x3D */      wkh_openwave_default,
1669         /* 0x3E */      wkh_openwave_default,           /* 0x3F */      wkh_openwave_default,
1670         /* 0x40 */      wkh_openwave_default,           /* 0x41 */      wkh_openwave_default,
1671         /* 0x42 */      wkh_openwave_default,           /* 0x43 */      wkh_openwave_default,
1672         /* 0x44 */      wkh_openwave_default,           /* 0x45 */      wkh_openwave_default,
1673         /* 0x46 */      wkh_openwave_default,           /* 0x47 */      wkh_openwave_default,
1674         /* 0x48 */      wkh_openwave_default,           /* 0x49 */      wkh_openwave_default,
1675         /* 0x4A */      wkh_openwave_default,           /* 0x4B */      wkh_openwave_default,
1676         /* 0x4C */      wkh_openwave_default,           /* 0x4D */      wkh_openwave_default,
1677         /* 0x4E */      wkh_openwave_default,           /* 0x4F */      wkh_openwave_default,
1678         /* 0x50 */      wkh_openwave_default,           /* 0x51 */      wkh_openwave_default,
1679         /* 0x52 */      wkh_openwave_default,           /* 0x53 */      wkh_openwave_default,
1680         /* 0x54 */      wkh_openwave_default,           /* 0x55 */      wkh_openwave_default,
1681         /* 0x56 */      wkh_openwave_default,           /* 0x57 */      wkh_openwave_default,
1682         /* 0x58 */      wkh_openwave_default,           /* 0x59 */      wkh_openwave_default,
1683         /* 0x5A */      wkh_openwave_default,           /* 0x5B */      wkh_openwave_default,
1684         /* 0x5C */      wkh_openwave_default,           /* 0x5D */      wkh_openwave_default,
1685         /* 0x5E */      wkh_openwave_default,           /* 0x5F */      wkh_openwave_default,
1686         /* 0x60 */      wkh_openwave_default,           /* 0x61 */      wkh_openwave_default,
1687         /* 0x62 */      wkh_openwave_default,           /* 0x63 */      wkh_openwave_default,
1688         /* 0x64 */      wkh_openwave_default,           /* 0x65 */      wkh_openwave_default,
1689         /* 0x66 */      wkh_openwave_default,           /* 0x67 */      wkh_openwave_default,
1690         /* 0x68 */      wkh_openwave_default,           /* 0x69 */      wkh_openwave_default,
1691         /* 0x6A */      wkh_openwave_default,           /* 0x6B */      wkh_openwave_default,
1692         /* 0x6C */      wkh_openwave_default,           /* 0x6D */      wkh_openwave_default,
1693         /* 0x6E */      wkh_openwave_default,           /* 0x6F */      wkh_openwave_default,
1694         /* 0x70 */      wkh_openwave_default,           /* 0x71 */      wkh_openwave_default,
1695         /* 0x72 */      wkh_openwave_default,           /* 0x73 */      wkh_openwave_default,
1696         /* 0x74 */      wkh_openwave_default,           /* 0x75 */      wkh_openwave_default,
1697         /* 0x76 */      wkh_openwave_default,           /* 0x77 */      wkh_openwave_default,
1698         /* 0x78 */      wkh_openwave_default,           /* 0x79 */      wkh_openwave_default,
1699         /* 0x7A */      wkh_openwave_default,           /* 0x7B */      wkh_openwave_default,
1700         /* 0x7C */      wkh_openwave_default,           /* 0x7D */      wkh_openwave_default,
1701         /* 0x7E */      wkh_openwave_default,           /* 0x7F */      wkh_openwave_default,
1702 }; 
1703
1704
1705
1706
1707
1708
1709 /* WSP header format
1710  *   1st byte: 0x00        : <Not allowed>
1711  *   1st byte: 0x01 -- 0x1F: <Shorthand Header Code Page switch>
1712  *   1st byte: 0x20 -- 0x7E: <Textual header (C string)>
1713  *       Followed with: <Textual header value (C string)>
1714  *   1st byte: 0x7F        : <Header Code Page switch>
1715  *       Followed with: 2nd byte: <Header Code Page>
1716  *   1st byte: 0x80 -- 0xFF: <Binary header (7-bit encoded ID)>
1717  *       Followed with:
1718  *         2nd byte: 0x00 -- 0x1E: <Value Length (bytes)>
1719  *             Followed with: <Len> bytes of data
1720  *         2nd byte: 0x1F        : <Value Length is a guintvar>
1721  *             Followed with: <guintvar Len>
1722  *             Followed with: <Len> bytes of data
1723  *         2nd byte: 0x20 -- 0x7F: <Textual header value (C string)>
1724  *         2nd byte: 0x80 -- 0xFF: <Binary value (7-bit encoded ID)>
1725  */
1726 static void
1727 add_headers (proto_tree *tree, tvbuff_t *tvb, int hf)
1728 {
1729         guint8 hdr_id, val_id, codepage = 1;
1730         gint32 tvb_len = tvb_length(tvb);
1731         gint32 offset = 0, hdr_len, hdr_start;
1732         gint32 val_len, val_start;
1733         guint8 *hdr_str, *val_str;
1734         proto_tree *wsp_headers;
1735         proto_item *ti;
1736         guint8 ok;
1737         guint32 val = 0;
1738         nstime_t tv;
1739
1740         if (offset >= tvb_len)
1741                 return; /* No headers! */
1742
1743         ti = proto_tree_add_item(tree, hf,
1744                         tvb, offset, tvb_len, bo_little_endian);
1745         wsp_headers = proto_item_add_subtree(ti, ett_headers);
1746
1747         while (offset < tvb_len) {
1748                 hdr_start = offset;
1749                 hdr_id = tvb_get_guint8(tvb, offset);
1750                 if (hdr_id & 0x80) { /* Well-known header */
1751                         hdr_len = 1;
1752                         val_start = ++offset;
1753                         val_id = tvb_get_guint8(tvb, val_start);
1754                         /* Call header value dissector for given header */
1755                         if (codepage == 1) { /* Default header code page */
1756                                 DebugLog(("add_headers(code page 0): %s\n",
1757                                                         match_strval (hdr_id & 0x7f, vals_field_names)));
1758                                 offset = WellKnownHeader[hdr_id & 0x7F](wsp_headers, tvb,
1759                                                 hdr_start);
1760                         } else { /* Openwave header code page */
1761                                 /* Here I'm delibarately assuming that Openwave is the only
1762                                  * company that defines a WSP header code page. */
1763                                 DebugLog(("add_headers(code page 0x%02x - assumed to be x-up-1): %s\n",
1764                                                         codepage, match_strval (hdr_id & 0x7f, vals_openwave_field_names)));
1765                                 offset = WellKnownOpenwaveHeader[hdr_id & 0x7F](wsp_headers,
1766                                                 tvb, hdr_start);
1767                         }
1768                 } else if (hdr_id == 0x7F) { /* HCP shift sequence */
1769                         codepage = tvb_get_guint8(tvb, offset+1);
1770                         proto_tree_add_uint(wsp_headers, hf_wsp_header_shift_code,
1771                                         tvb, offset, 2, codepage);
1772                         offset += 2;
1773                 } else if (hdr_id >= 0x20) { /* Textual header */
1774                         /* Header name MUST be NUL-ended string ==> tvb_get_stringz() */
1775                         hdr_str = tvb_get_stringz(tvb, hdr_start, &hdr_len);
1776                         val_start = hdr_start + hdr_len;
1777                         val_id = tvb_get_guint8(tvb, val_start);
1778                         /* Call header value dissector for given header */
1779                         if (val_id >= 0x20 && val_id <=0x7E) { /* OK! */
1780                                 val_str = tvb_get_stringz(tvb, val_start, &val_len);
1781                                 g_assert(val_str);
1782                                 offset = val_start + val_len;
1783                                 proto_tree_add_text(wsp_headers,tvb,hdr_start,offset-hdr_start,
1784                                                 "%s: %s", hdr_str, val_str);
1785                                 g_free (val_str);
1786                         } else {
1787                                 /* Old-style X-WAP-TOD uses a non-textual value
1788                                  * after a textual header. */
1789                                 if (strcasecmp(hdr_str, "x-wap.tod") == 0) {
1790                                         get_delta_seconds_value(val, tvb, val_start, val_len, ok);
1791                                         if (ok) {
1792                                                 if (val == 0) {
1793                                                         ti = proto_tree_add_string (wsp_headers,
1794                                                                         hf_hdr_x_wap_tod,
1795                                                                         tvb, hdr_start, hdr_len + val_len,
1796                                                                         "Requesting Time Of Day");
1797                                                 } else {
1798                                                         tv.secs = val;
1799                                                         tv.nsecs = 0;
1800                                                         val_str = abs_time_to_str(&tv);
1801                                                         g_assert (val_str);
1802                                                         ti = proto_tree_add_string (wsp_headers,
1803                                                                         hf_hdr_x_wap_tod,
1804                                                                         tvb, hdr_start, hdr_len + val_len, val_str);
1805                                                 }
1806                                                 proto_item_append_text(ti, " <Warning: "
1807                                                                 "should be encoded as a textual value>");
1808                                         } else {
1809                                                 /* I prefer using X-Wap-Tod to the real hdr_str */
1810                                                 proto_tree_add_string (wsp_headers, hf_hdr_x_wap_tod,
1811                                                                 tvb, hdr_start, hdr_len + val_len,
1812                                                                 InvalidValueForHeader("X-Wap-Tod"));
1813                                         }
1814                                 } else {
1815                                         proto_tree_add_text (wsp_headers, tvb, hdr_start, hdr_len,
1816                                                         "<Error: Invalid value for the textual '%s' header"
1817                                                         " (should be a textual value)>",
1818                                                         hdr_str);
1819                                 }
1820                                 offset = tvb_len;
1821                         }
1822                         proto_tree_add_string_hidden(wsp_headers, hf_hdr_name,
1823                                         tvb, hdr_start, offset - hdr_start, hdr_str);
1824                 } else if (hdr_id > 0) { /* Shorthand HCP switch */
1825                         codepage = hdr_id;
1826                         proto_tree_add_uint (wsp_headers, hf_wsp_header_shift_code,
1827                                         tvb, offset, 1, codepage);
1828                         offset++;
1829                 } else {
1830                         proto_tree_add_text (wsp_headers, tvb, hdr_start, 1,
1831                                         InvalidTextualHeader);
1832                         offset = tvb_len;
1833                 }
1834         }
1835 }
1836
1837
1838 /* The following macros hide common processing for all well-known headers
1839  * and shortens the code to be written in a wkh_XXX() function.
1840  * Even declarations are hidden by a macro.
1841  *
1842  * Define a wkh_XXX() function as follows:
1843  *
1844  * static guint32
1845  * wkh_XXX (proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
1846  * {
1847  *              wkh_0_Declarations;
1848  *              << add other required declarations here >>
1849  *
1850  *              wkh_1_WellKnownValue;
1851  *                      << add well-known value proto item here; don't forget to set the
1852  *                      ok variable to TRUE if parsing was correct >>
1853  *              wkh_2_TextualValue;
1854  *                      << add textual value proto item here; don't forget to set the
1855  *                      ok variable to TRUE if parsing was correct >>
1856  *              wkh_3_ValueWithLength;
1857  *                      << add custom code for value processing and value proto item here >>
1858  *
1859  *              wkh_4_End(hf);
1860  *                      << This macro takes care of parse errors within the header value;
1861  *                      it requires the header field index if the header has not yet been
1862  *                      written to the protocol tree (ti == NULL). >>
1863  * }
1864  *
1865  *      NOTE:   You only need to write parsing code for the successful case,
1866  *                      Errors are automatically reported through the wkh_4_End() macro
1867  *                      when ok <> TRUE.
1868  */
1869
1870 /* The following code is the generic template with which the value of a
1871  * well-known header can be processed. Not all sections yield a semantically
1872  * correct result, so appropriate error information must be provided.
1873  */
1874
1875
1876 #define wkh_0_Declarations                                      /* Declarations for Parsing */ \
1877         gboolean ok = FALSE; /* Triggers error notification code at end */ \
1878         proto_item *ti = NULL; /* Needed for error notification at end */ \
1879         guint32 val_start = hdr_start + 1; \
1880         guint8 hdr_id = tvb_get_guint8 (tvb, hdr_start) & 0x7F; \
1881         guint8 val_id = tvb_get_guint8 (tvb, val_start); \
1882         guint32 offset = val_start; /* Offset to one past this header */ \
1883         guint32 val_len; /* length for value with length field */ \
1884         guint32 val_len_len; /* length of length field */ \
1885         guint8 *val_str = NULL
1886
1887 #define wkh_1_WellKnownValue                            /* Parse Well Known Value */ \
1888         proto_tree_add_string_hidden(tree, hf_hdr_name, \
1889                         tvb, hdr_start, offset - hdr_start, \
1890                         val_to_str (hdr_id, vals_field_names, \
1891                                 "<Unknown WSP header field 0x%02X>")); \
1892         if (val_id & 0x80) { /* Well-known value */ \
1893                 offset++; \
1894                 /* Well-known value processing starts HERE \
1895                  * \
1896                  * BEGIN */
1897
1898 #define wkh_2_TextualValue                                      /* Parse Textual Value */ \
1899                 /* END */ \
1900         } else if ((val_id == 0) || (val_id >= 0x20)) { /* Textual value */ \
1901                 val_str = tvb_get_stringz (tvb, val_start, &val_len); \
1902                 g_assert(val_str); \
1903                 offset = val_start + val_len; \
1904                 /* Textual value processing starts HERE \
1905                  * \
1906                  * BEGIN */
1907
1908 #define wkh_3_ValueWithLength                           /* Parse Value With Length */ \
1909                 /* END */ \
1910                 g_free(val_str); \
1911         } else { /* val_start points to 1st byte of length field */ \
1912                 if (val_id == 0x1F) { /* Value Length = guintvar */ \
1913                         val_len = tvb_get_guintvar(tvb, val_start + 1, &val_len_len); \
1914                         val_len_len++; /* 0x1F length indicator byte */ \
1915                 } else { /* Short length followed by Len data octets */ \
1916                         val_len = tvb_get_guint8(tvb, offset); \
1917                         val_len_len = 1; \
1918                 } \
1919                 offset += val_len_len + val_len; \
1920                 /* Value with length processing starts HERE \
1921                  * The value lies between val_start and offset: \
1922                  *  - Value Length:     Start  = val_start \
1923                  *                                      Length = val_len_len \
1924                  *  - Value Data  :     Start  = val_start + val_len_len \
1925                  *                                      Length = val_len \
1926                  *                                      End    = offset - 1 \
1927                  * BEGIN */
1928
1929 #define wkh_4_End(hf)                                           /* End of value parsing */ \
1930                 /* END */ \
1931         } \
1932         /* Check for errors */ \
1933         if (! ok) { \
1934                 if (ti) { /* Append to protocol tree item label */ \
1935                         proto_item_append_text(ti, \
1936                                         " <Error: Invalid header value>"); \
1937                 } else if (hf > 0) { /* Create protocol tree item */ \
1938                         proto_tree_add_string(tree, hf, \
1939                                         tvb, hdr_start, offset - hdr_start, \
1940                                         " <Error: Invalid header value>"); \
1941                 } else { /* Create anonymous header field entry */ \
1942                         proto_tree_add_text(tree, tvb, hdr_start, offset - hdr_start, \
1943                                         "%s: <Error: Invalid header value>", \
1944                                         val_to_str (hdr_id, vals_field_names, \
1945                                                 "<Unknown WSP header field 0x%02X>")); \
1946                 } \
1947         } \
1948         return offset;
1949
1950
1951 /*
1952  * This yields the following default header value parser function body
1953  */
1954 static guint32
1955 wkh_default(proto_tree *tree, tvbuff_t *tvb,
1956                 guint32 hdr_start)
1957 {
1958         wkh_0_Declarations;
1959
1960         ok = TRUE; /* Bypass error checking as we don't parse the values! */
1961
1962         wkh_1_WellKnownValue;
1963                 ti = proto_tree_add_text (tree, tvb, hdr_start, offset - hdr_start,
1964                                 "%s: (Undecoded well-known value 0x%02x)",
1965                                 val_to_str (hdr_id, vals_field_names,
1966                                         "<Unknown WSP header field 0x%02X>"), val_id & 0x7F);
1967         wkh_2_TextualValue;
1968                 ti = proto_tree_add_text(tree, tvb, hdr_start, offset - hdr_start,
1969                                 "%s: %s",
1970                                 val_to_str (hdr_id, vals_field_names,
1971                                         "<Unknown WSP header field 0x%02X>"), val_str);
1972         wkh_3_ValueWithLength;
1973                 ti = proto_tree_add_text (tree, tvb, hdr_start, offset - hdr_start,
1974                                 "%s: (Undecoded value in general form with length indicator)",
1975                                 val_to_str (hdr_id, vals_field_names,
1976                                         "<Unknown WSP header field 0x%02X>"));
1977
1978         wkh_4_End(HF_EMPTY); /* The default parser has no associated hf_index;
1979                                                         additionally the error code is always bypassed */
1980 }
1981
1982
1983 /* Content-type processing uses the following common core: */
1984 #define wkh_content_type_header(underscored,Text) \
1985 static guint32 \
1986 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
1987 { \
1988         wkh_0_Declarations; \
1989         guint32 off, val = 0, len; \
1990         guint8 peek; \
1991         proto_tree *parameter_tree = NULL; \
1992         \
1993         wkh_1_WellKnownValue; \
1994                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
1995                                 tvb, hdr_start, offset - hdr_start, \
1996                                 val_to_str(val_id & 0x7F, vals_content_types, \
1997                                         "(Unknown content type identifier 0x%X)")); \
1998                 ok = TRUE; \
1999         wkh_2_TextualValue; \
2000                 /* Sometimes with a No-Content response, a NULL content type \
2001                  * is reported. Process this correctly! */ \
2002                 if (*val_str) { \
2003                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2004                                         tvb, hdr_start, offset - hdr_start, \
2005                                         val_str); \
2006                 } else { \
2007                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2008                                         tvb, hdr_start, offset - hdr_start, \
2009                                         "<no content type has been specified>"); \
2010                 } \
2011                 ok = TRUE; \
2012         wkh_3_ValueWithLength; \
2013                 off = val_start + val_len_len; \
2014                 peek = tvb_get_guint8(tvb, off); \
2015                 if (is_text_string(peek)) { \
2016                         get_extension_media(val_str, tvb, off, len, ok); \
2017                         /* As we're using val_str, it is automatically g_free()d */ \
2018                         off += len; /* off now points to 1st byte after string */ \
2019                         ti = proto_tree_add_string (tree, hf_hdr_ ## underscored, \
2020                                         tvb, hdr_start, offset - hdr_start, val_str); \
2021                 } else if (is_integer_value(peek)) { \
2022                         get_integer_value(val, tvb, off, len, ok); \
2023                         if (ok) { \
2024                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2025                                                 tvb, hdr_start, offset - hdr_start, \
2026                                                 val_to_str(val, vals_content_types, \
2027                                                         "(Unknown content type identifier 0x%X)")); \
2028                         } \
2029                         off += len; \
2030                 } \
2031                 /* Remember: offset == val_start + val_len + val_len_len */ \
2032                 if (ok && (off < offset)) { /* Add parameters if any */ \
2033                         parameter_tree = proto_item_add_subtree (ti, ett_header); \
2034                         while (off < offset) { \
2035                                 off = parameter (parameter_tree, ti, tvb, off, offset - off); \
2036                         } \
2037                 } \
2038         \
2039         wkh_4_End(hf_hdr_ ## underscored); \
2040 }
2041
2042
2043 /*
2044  * Accept-value =
2045  *        Short-integer
2046  *      | Extension-media
2047  *      | ( Value-length ( Extension-media | Integer-value ) *( Parameter ) )
2048  */
2049 wkh_content_type_header(accept, "Accept")
2050
2051
2052 /*
2053  * Content-type-value =
2054  *        Short-integer
2055  *      | Extension-media
2056  *      | ( Value-length ( Extension-media | Integer-value ) *( Parameter ) )
2057  *
2058  * Beware: this header should not appear as such; it is dissected elsewhere
2059  * and at the same time the content type is used for subdissectors.
2060  * It is here for the sake of completeness.
2061  */
2062 wkh_content_type_header(content_type, "Content-Type")
2063
2064
2065 /*
2066  * Content-type-value =
2067  *        Short-integer
2068  *      | Extension-media
2069  *      | ( Value-length ( Extension-media | Integer-value ) *( Parameter ) )
2070  *
2071  * This function adds the content type value to the protocol tree,
2072  * and computes either the numeric or textual media type in return,
2073  * which will be used for further subdissection (e.g., MMS, WBXML).
2074  */
2075 guint32
2076 add_content_type(proto_tree *tree, tvbuff_t *tvb, guint32 val_start,
2077                 guint32 *well_known_content, const char **textual_content)
2078 {
2079         /* Replace wkh_0_Declarations with slightly modified declarations
2080          * so we can still make use of the wkh_[1-4]_XXX macros! */
2081         guint32 hdr_start = val_start; /* No header name, only value! */
2082         guint8 hdr_id = FN_CONTENT_TYPE; /* Same remark */
2083         guint8 val_id = tvb_get_guint8 (tvb, val_start);
2084         guint32 offset = val_start; /* Offset to one past this header */
2085         guint32 val_len; /* length for value with length field */
2086         guint32 val_len_len; /* length of length field */
2087         guint8 *val_str = NULL;
2088         guint32 off, val = 0, len;
2089         guint8 peek;
2090         gboolean ok = FALSE;
2091         proto_item *ti = NULL;
2092         proto_tree *parameter_tree = NULL;
2093
2094         *textual_content = NULL;
2095         *well_known_content = 0;
2096
2097         DebugLog(("add_content_type() - START\n"));
2098
2099         wkh_1_WellKnownValue;
2100                 DebugLog(("add_content_type() - Well-known - Start\n"));
2101                 *textual_content = val_to_str(val_id & 0x7F, vals_content_types,
2102                                 "<Unknown media type identifier 0x%X>");
2103                 ti = proto_tree_add_string(tree, hf_hdr_content_type,
2104                                 tvb, hdr_start, offset - hdr_start,
2105                                 *textual_content);
2106                 *well_known_content = val_id & 0x7F;
2107                 ok = TRUE;
2108                 DebugLog(("add_content_type() - Well-known - End\n"));
2109         wkh_2_TextualValue;
2110                 DebugLog(("add_content_type() - Textual - Start\n"));
2111                 /* Sometimes with a No-Content response, a NULL content type
2112                  * is reported. Process this correctly! */
2113                 if (*val_str) {
2114                         ti = proto_tree_add_string(tree, hf_hdr_content_type,
2115                                         tvb, hdr_start, offset - hdr_start,
2116                                         val_str);
2117                         /* As we're using val_str, it is automatically g_free()d */
2118                         *textual_content = g_strdup(val_str);
2119                         *well_known_content = 0;
2120                 } else {
2121                         ti = proto_tree_add_string(tree, hf_hdr_content_type,
2122                                         tvb, hdr_start, offset - hdr_start,
2123                                         "<no media type has been specified>");
2124                         *textual_content = NULL;
2125                         *well_known_content = 0;
2126                 }
2127                 ok = TRUE;
2128                 DebugLog(("add_content_type() - Textual - End\n"));
2129         wkh_3_ValueWithLength;
2130                 DebugLog(("add_content_type() - General form - Start\n"));
2131                 off = val_start + val_len_len;
2132                 peek = tvb_get_guint8(tvb, off);
2133                 if (is_text_string(peek)) {
2134                         DebugLog(("add_content_type() - General form - extension-media\n"));
2135                         get_extension_media(val_str, tvb, off, len, ok);
2136                         /* As we're using val_str, it is automatically g_free()d */
2137                         /* ??? Not sure anymore, we're in wkh_3, not in wkh_2 ! */
2138                         off += len; /* off now points to 1st byte after string */
2139                         ti = proto_tree_add_string (tree, hf_hdr_content_type,
2140                                         tvb, hdr_start, offset - hdr_start, val_str);
2141                         /* Following statement: required? */
2142                         *textual_content = g_strdup(val_str);
2143                         *well_known_content = 0;
2144                 } else if (is_integer_value(peek)) {
2145                         DebugLog(("add_content_type() - General form - integer_value\n"));
2146                         get_integer_value(val, tvb, off, len, ok);
2147                         if (ok) {
2148                                 *textual_content = val_to_str(val, vals_content_types,
2149                                                 "<Unknown media type identifier 0x%X>");
2150                                 ti = proto_tree_add_string(tree, hf_hdr_content_type,
2151                                                 tvb, hdr_start, offset - hdr_start,
2152                                                 *textual_content);
2153                                 *well_known_content = val;
2154                         }
2155                         off += len;
2156                 } /* else ok = FALSE */
2157                 /* Remember: offset == val_start + val_len_len + val_len */
2158                 if (ok && (off < offset)) { /* Add parameters if any */
2159                         DebugLog(("add_content_type() - General form - parameters\n"));
2160                         parameter_tree = proto_item_add_subtree (ti, ett_header);
2161                         while (off < offset) {
2162                                 DebugLog(("add_content_type() - General form - parameter start "
2163                                                         "(off = %u)\n", off));
2164                                 off = parameter (parameter_tree, ti, tvb, off, offset - off);
2165                                 DebugLog(("add_content_type() - General form - parameter end "
2166                                                         "(off = %u)\n", off));
2167                         }
2168                 }
2169                 DebugLog(("add_content_type() - General form - End\n"));
2170
2171         wkh_4_End(hf_hdr_content_type);
2172 }
2173
2174
2175 /*
2176  * Template for accept_X headers with optional Q parameter value
2177  */
2178 #define wkh_accept_x_q_header(underscored,Text,valueString,valueName) \
2179 static guint32 \
2180 wkh_ ## underscored (proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2181 { \
2182         wkh_0_Declarations; \
2183         guint32 off, val = 0, len; \
2184         guint8 peek; \
2185         proto_tree *parameter_tree = NULL; \
2186         \
2187         wkh_1_WellKnownValue; \
2188                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2189                                 tvb, hdr_start, offset - hdr_start, \
2190                                 val_to_str(val_id & 0x7F, valueString, \
2191                                         "<Unknown " valueName " identifier 0x%X>")); \
2192                 ok = TRUE; \
2193         wkh_2_TextualValue; \
2194                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2195                                 tvb, hdr_start, offset - hdr_start, val_str); \
2196                 ok = TRUE; \
2197         wkh_3_ValueWithLength; \
2198                 off = val_start + val_len_len; \
2199                 peek = tvb_get_guint8(tvb, off); \
2200                 if (is_text_string(peek)) { \
2201                         get_token_text(val_str, tvb, off, len, ok); \
2202                         /* As we're using val_str, it is automatically g_free()d */ \
2203                         off += len; /* off now points to 1st byte after string */ \
2204                         ti = proto_tree_add_string (tree, hf_hdr_ ## underscored, \
2205                                         tvb, hdr_start, offset - hdr_start, val_str); \
2206                 } else if (is_integer_value(peek)) { \
2207                         get_integer_value(val, tvb, off, len, ok); \
2208                         if (ok) { \
2209                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2210                                                 tvb, hdr_start, offset - hdr_start, \
2211                                                 val_to_str(val, valueString, \
2212                                                         "<Unknown " valueName " identifier 0x%X>")); \
2213                         } \
2214                         off += len; \
2215                 } /* else ok = FALSE */ \
2216                 /* Remember: offset == val_start + val_len */ \
2217                 if (ok && (off < offset)) { /* Add Q-value if available */ \
2218                         parameter_tree = proto_item_add_subtree (ti, ett_header); \
2219                         off = parameter_value_q (parameter_tree, ti, tvb, off); \
2220                 } \
2221         \
2222         wkh_4_End(hf_hdr_ ## underscored); \
2223 }
2224
2225 /*
2226  * Accept-charset-value =
2227  *        Short-integer
2228  *      | Extension-media
2229  *      | ( Value-length ( Token-text | Integer-value ) [ Q-value ] )
2230  */
2231 wkh_accept_x_q_header(accept_charset, "Accept-Charset",
2232                 vals_character_sets, "character set")
2233 /*
2234  * Accept-language-value =
2235  *        Short-integer
2236  *      | Extension-media
2237  *      | ( Value-length ( Text-string | Integer-value ) [ Q-value ] )
2238  */
2239 wkh_accept_x_q_header(accept_language, "Accept-Language",
2240                 vals_languages, "language")
2241
2242
2243 /*
2244  * Push-flag-value = Short-integer
2245  */
2246 static guint32
2247 wkh_push_flag(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2248 {
2249         wkh_0_Declarations;
2250         proto_tree *subtree = NULL;
2251
2252         wkh_1_WellKnownValue;
2253                 ti = proto_tree_add_string(tree, hf_hdr_push_flag,
2254                                 tvb, hdr_start, offset - hdr_start, "");
2255                 subtree = proto_item_add_subtree(ti, ett_header);
2256                 proto_tree_add_uint(subtree, hf_hdr_push_flag_auth,
2257                                 tvb, val_start, 1, val_id);
2258                 proto_tree_add_uint(subtree, hf_hdr_push_flag_trust,
2259                                 tvb, val_start, 1, val_id);
2260                 proto_tree_add_uint(subtree, hf_hdr_push_flag_last,
2261                                 tvb, val_start, 1, val_id);
2262                 if (val_id & 0x01)
2263                         proto_item_append_string(ti, " (Initiator URI authenticated)");
2264                 if (val_id & 0x02)
2265                         proto_item_append_string(ti, " (Content trusted)");
2266                 if (val_id & 0x04)
2267                         proto_item_append_string(ti, " (Last push message)");
2268                 if (val_id & 0x78)
2269                         proto_item_append_text(ti, " <Warning: Reserved flags set>");
2270                 else
2271                         ok = TRUE;
2272         wkh_2_TextualValue;
2273                 /* Invalid */
2274         wkh_3_ValueWithLength;
2275                 /* Invalid */
2276         wkh_4_End(hf_hdr_push_flag);
2277 }
2278
2279
2280 /*
2281  * Allow-value =
2282  *     Short-integer
2283  */
2284 static guint32
2285 wkh_allow(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2286 {
2287         wkh_0_Declarations;
2288
2289         wkh_1_WellKnownValue;
2290                 val_id &= 0x7F;
2291                 if (val_id >= 0x40) { /* Valid WSP method */
2292                         ti = proto_tree_add_string(tree, hf_hdr_allow,
2293                                         tvb, hdr_start, offset - hdr_start,
2294                                         val_to_str(val_id & 0x7F, vals_pdu_type,
2295                                                 "<Unknown WSP method 0x%02X>"));
2296                         ok = TRUE;
2297                 }
2298         wkh_2_TextualValue;
2299                 /* Invalid */
2300         wkh_3_ValueWithLength;
2301                 /* Invalid */
2302         wkh_4_End(hf_hdr_allow);
2303 }
2304
2305
2306 /*
2307  * Public-value =
2308  *     Token-text | Short-integer
2309  */
2310 static guint32
2311 wkh_public(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2312 {
2313         wkh_0_Declarations;
2314
2315         wkh_1_WellKnownValue;
2316                 val_id &= 0x7F;
2317                 if (val_id >= 0x40) { /* Valid WSP method */
2318                         ti = proto_tree_add_string(tree, hf_hdr_public,
2319                                         tvb, hdr_start, offset - hdr_start,
2320                                         val_to_str(val_id & 0x7F, vals_pdu_type,
2321                                                 "<Unknown WSP method 0x%02X>"));
2322                         ok = TRUE;
2323                 }
2324         wkh_2_TextualValue;
2325                 ti = proto_tree_add_string(tree, hf_hdr_public,
2326                                 tvb, hdr_start, offset - hdr_start, val_str);
2327                 ok = TRUE;
2328         wkh_3_ValueWithLength;
2329                 /* Invalid */
2330         wkh_4_End(hf_hdr_public);
2331 }
2332
2333
2334 /*
2335  * Vary-value =
2336  *     Token-text | Short-integer
2337  */
2338 static guint32
2339 wkh_vary(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2340 {
2341         wkh_0_Declarations;
2342
2343         wkh_1_WellKnownValue;
2344                 ti = proto_tree_add_string(tree, hf_hdr_vary,
2345                                 tvb, hdr_start, offset - hdr_start,
2346                                 val_to_str(val_id & 0x7F, vals_field_names,
2347                                         "<Unknown WSP header field 0x%02X>"));
2348                 ok = TRUE;
2349         wkh_2_TextualValue;
2350                 ti = proto_tree_add_string(tree, hf_hdr_vary,
2351                                 tvb, hdr_start, offset - hdr_start,
2352                                 val_str);
2353                 ok = TRUE;
2354         wkh_3_ValueWithLength;
2355                 /* Invalid */
2356         wkh_4_End(hf_hdr_vary);
2357 }
2358
2359
2360 /*
2361  * X-wap-security-value = 0x80
2362  */
2363 static guint32
2364 wkh_x_wap_security(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2365 {
2366         wkh_0_Declarations;
2367
2368         wkh_1_WellKnownValue;
2369                 if (val_id == 0x80) {
2370                         ti = proto_tree_add_string(tree, hf_hdr_x_wap_security,
2371                                         tvb, hdr_start, offset - hdr_start, "close-subordinate");
2372                         ok = TRUE;
2373                 }
2374         wkh_2_TextualValue;
2375                 /* Invalid */
2376         wkh_3_ValueWithLength;
2377                 /* Invalid */
2378         wkh_4_End(hf_hdr_x_wap_security);
2379 }
2380
2381
2382 /*
2383  * Connection-value = 0x80 | Token-text
2384  */
2385 static guint32
2386 wkh_connection(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2387 {
2388         wkh_0_Declarations;
2389
2390         wkh_1_WellKnownValue;
2391                 if (val_id == 0x80) {
2392                         ti = proto_tree_add_string(tree, hf_hdr_connection,
2393                                         tvb, hdr_start, offset - hdr_start, "close");
2394                         ok = TRUE;
2395                 }
2396         wkh_2_TextualValue;
2397                 ti = proto_tree_add_string(tree, hf_hdr_connection,
2398                                 tvb, hdr_start, offset - hdr_start, val_str);
2399                 ok = TRUE;
2400         wkh_3_ValueWithLength;
2401                 /* Invalid */
2402         wkh_4_End(hf_hdr_connection);
2403 }
2404
2405
2406 /*
2407  * Transfer-encoding-value = 0x80 | Token-text
2408  */
2409 static guint32
2410 wkh_transfer_encoding(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2411 {
2412         wkh_0_Declarations;
2413
2414         wkh_1_WellKnownValue;
2415                 if (val_id == 0x80) {
2416                         ti = proto_tree_add_string(tree, hf_hdr_transfer_encoding,
2417                                         tvb, hdr_start, offset - hdr_start, "chunked");
2418                         ok = TRUE;
2419                 }
2420         wkh_2_TextualValue;
2421                 ti = proto_tree_add_string(tree, hf_hdr_transfer_encoding,
2422                                 tvb, hdr_start, offset - hdr_start, val_str);
2423                 ok = TRUE;
2424         wkh_3_ValueWithLength;
2425                 /* Invalid */
2426         wkh_4_End(hf_hdr_transfer_encoding);
2427 }
2428
2429
2430 /*
2431  * Accept-range-value = 0x80 | 0x81 | Token-text
2432  */
2433 static guint32
2434 wkh_accept_ranges(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2435 {
2436         wkh_0_Declarations;
2437
2438         wkh_1_WellKnownValue;
2439                 switch (val_id) {
2440                         case 0x80: /* none */
2441                                 ti = proto_tree_add_string(tree, hf_hdr_accept_ranges,
2442                                                 tvb, hdr_start, offset - hdr_start, "none");
2443                                 ok = TRUE;
2444                                 break;
2445                         case 0x81: /* bytes */
2446                                 ti = proto_tree_add_string(tree, hf_hdr_accept_ranges,
2447                                                 tvb, hdr_start, offset - hdr_start, "bytes");
2448                                 ok = TRUE;
2449                                 break;
2450                 }
2451         wkh_2_TextualValue;
2452                 ti = proto_tree_add_string(tree, hf_hdr_accept_ranges,
2453                                 tvb, hdr_start, offset - hdr_start, val_str);
2454                 ok = TRUE;
2455         wkh_3_ValueWithLength;
2456                 /* Invalid */
2457         wkh_4_End(hf_hdr_accept_ranges);
2458 }
2459
2460
2461 /*
2462  * Content-encoding-value = 0x80 | 0x81 | 0x82 | Token-text
2463  */
2464 static guint32
2465 wkh_content_encoding(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2466 {
2467         wkh_0_Declarations;
2468
2469         wkh_1_WellKnownValue;
2470                 switch (val_id) {
2471                         case 0x80: /* gzip */
2472                                 ti = proto_tree_add_string(tree, hf_hdr_content_encoding,
2473                                                 tvb, hdr_start, offset - hdr_start, "gzip");
2474                                 ok = TRUE;
2475                                 break;
2476                         case 0x81: /* compress */
2477                                 ti = proto_tree_add_string(tree, hf_hdr_content_encoding,
2478                                                 tvb, hdr_start, offset - hdr_start, "compress");
2479                                 ok = TRUE;
2480                                 break;
2481                         case 0x82: /* deflate */
2482                                 ti = proto_tree_add_string(tree, hf_hdr_content_encoding,
2483                                                 tvb, hdr_start, offset - hdr_start, "deflate");
2484                                 ok = TRUE;
2485                                 break;
2486                 }
2487         wkh_2_TextualValue;
2488                 ti = proto_tree_add_string(tree, hf_hdr_content_encoding,
2489                                 tvb, hdr_start, offset - hdr_start, val_str);
2490                 ok = TRUE;
2491         wkh_3_ValueWithLength;
2492                 /* Invalid */
2493         wkh_4_End(hf_hdr_content_encoding);
2494 }
2495
2496
2497 /*
2498  * Accept-encoding-value =
2499  *        Short-integer
2500  *      | Token-text
2501  *      | ( Value-length ( Short-integer | Text-string ) [ Q-value ] )
2502  */
2503 static guint32
2504 wkh_accept_encoding(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2505 {
2506         wkh_0_Declarations;
2507         guint32 len, off;
2508         guint8 peek;
2509         gchar *str;
2510         proto_tree *parameter_tree = NULL;
2511
2512         wkh_1_WellKnownValue;
2513                 switch (val_id) {
2514                         case 0x80: /* gzip */
2515                                 ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2516                                                 tvb, hdr_start, offset - hdr_start, "gzip");
2517                                 ok = TRUE;
2518                                 break;
2519                         case 0x81: /* compress */
2520                                 ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2521                                                 tvb, hdr_start, offset - hdr_start, "compress");
2522                                 ok = TRUE;
2523                                 break;
2524                         case 0x82: /* deflate */
2525                                 ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2526                                                 tvb, hdr_start, offset - hdr_start, "deflate");
2527                                 ok = TRUE;
2528                                 break;
2529                 }
2530         wkh_2_TextualValue;
2531                 proto_tree_add_string(tree, hf_hdr_accept_encoding,
2532                                 tvb, hdr_start, offset - hdr_start, val_str);
2533                 ok = TRUE;
2534         wkh_3_ValueWithLength;
2535                 off = val_start + val_len_len;
2536                 peek = tvb_get_guint8(tvb, off);
2537                 if (is_short_integer(peek)) {
2538                         switch (val_id) {
2539                                 case 0x80: /* gzip */
2540                                         ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2541                                                         tvb, hdr_start, offset - hdr_start, "gzip");
2542                                         ok = TRUE;
2543                                         break;
2544                                 case 0x81: /* compress */
2545                                         ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2546                                                         tvb, hdr_start, offset - hdr_start, "compress");
2547                                         ok = TRUE;
2548                                         break;
2549                                 case 0x82: /* deflate */
2550                                         ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2551                                                         tvb, hdr_start, offset - hdr_start, "deflate");
2552                                         ok = TRUE;
2553                                         break;
2554                                 case 0x83: /* any */
2555                                         ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2556                                                         tvb, hdr_start, offset - hdr_start, "*");
2557                                         ok = TRUE;
2558                                         break;
2559                         }
2560                         off++;
2561                 } else {
2562                         get_token_text(str, tvb, off, len, ok);
2563                         if (ok) {
2564                                 ti = proto_tree_add_string(tree, hf_hdr_accept_encoding,
2565                                                 tvb, hdr_start, offset - hdr_start, str);
2566                                 g_free(str);
2567                         }
2568                         off += len;
2569                 }
2570                 if (ok) {
2571                         /* Remember: offset == val_start + val_len_len + val_len */
2572                         if (off < offset) { /* Add Q-value if available */
2573                                 parameter_tree = proto_item_add_subtree(ti, ett_header);
2574                                 off = parameter_value_q(parameter_tree, ti, tvb, off);
2575                         }
2576                 }
2577         wkh_4_End(hf_hdr_accept_encoding);
2578 }
2579
2580
2581 /*
2582  * Content-disposition-value = Value-length ( Disposition ) *( Parameter )
2583  *      Disposition = Form-data | Attachment | Inline | Token-text
2584  *      Form-data = 0x80
2585  *      Attachment = 0x81
2586  *      Inline = 0x82
2587  * We handle this as:
2588  *      Value-length ( Short-integer | Text-string ) *( Parameter )
2589  */
2590 static guint32
2591 wkh_content_disposition(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2592 {
2593         wkh_0_Declarations;
2594         guint32 len, off;
2595         guint8 peek;
2596         gchar *str;
2597         proto_tree *parameter_tree = NULL;
2598
2599         wkh_1_WellKnownValue;
2600                 /* Invalid */
2601         wkh_2_TextualValue;
2602                 /* Invalid */
2603         wkh_3_ValueWithLength;
2604                 off = val_start + val_len_len;
2605                 peek = tvb_get_guint8(tvb, off);
2606                 if (is_short_integer(peek)) {
2607                         switch (peek) {
2608                                 case 0x80: /* form-data */
2609                                         ti = proto_tree_add_string(tree, hf_hdr_content_disposition,
2610                                                         tvb, hdr_start, offset - hdr_start, "form-data");
2611                                         ok = TRUE;
2612                                         break;
2613                                 case 0x81: /* attachment */
2614                                         ti = proto_tree_add_string(tree, hf_hdr_content_disposition,
2615                                                         tvb, hdr_start, offset - hdr_start, "attachment");
2616                                         ok = TRUE;
2617                                         break;
2618                                 case 0x82: /* inline */
2619                                         ti = proto_tree_add_string(tree, hf_hdr_content_disposition,
2620                                                         tvb, hdr_start, offset - hdr_start, "inline");
2621                                         ok = TRUE;
2622                                         break;
2623                         }
2624                         off++;
2625                 } else {
2626                         get_token_text(str, tvb, off, len, ok);
2627                         if (ok) {
2628                                 ti = proto_tree_add_string(tree, hf_hdr_content_disposition,
2629                                                 tvb, hdr_start, offset - hdr_start, str);
2630                                 g_free(str);
2631                         }
2632                         off += len;
2633                 }
2634                 if ((ok) && (off < offset)) {
2635                         /* Remember: offset == val_start + val_len_len + val_len */
2636                         parameter_tree = proto_item_add_subtree(ti, ett_header);
2637                         while (off < offset) { /* Add parameters if available */
2638                                 off = parameter(parameter_tree, ti, tvb, off, offset - off);
2639                         }
2640                 }
2641         wkh_4_End(hf_hdr_content_disposition);
2642 }
2643
2644
2645 /*
2646  * Common code for headers with only a textual value
2647  * is written in the macro below:
2648  */
2649 #define wkh_text_header(underscored,Text) \
2650 static guint32 \
2651 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2652 { \
2653         wkh_0_Declarations; \
2654         \
2655         wkh_1_WellKnownValue; \
2656                 /* Invalid */ \
2657         wkh_2_TextualValue; \
2658                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2659                                 tvb, hdr_start, offset - hdr_start, val_str); \
2660                 ok = TRUE; \
2661         wkh_3_ValueWithLength; \
2662                 /* Invalid */ \
2663         wkh_4_End(hf_hdr_ ## underscored); \
2664 }
2665
2666 /* Text-only headers: */
2667 wkh_text_header(content_base, "Content-Base")
2668 wkh_text_header(content_location, "Content-Location")
2669 wkh_text_header(etag, "ETag")
2670 wkh_text_header(from, "From")
2671 wkh_text_header(host, "Host")
2672 wkh_text_header(if_match, "If-Match")
2673 wkh_text_header(if_none_match, "If-None-Match")
2674 wkh_text_header(location, "Location")
2675 wkh_text_header(referer, "Referer")
2676 wkh_text_header(server, "Server")
2677 wkh_text_header(user_agent, "User-Agent")
2678 wkh_text_header(upgrade, "Upgrade")
2679 wkh_text_header(via, "Via")
2680 wkh_text_header(content_uri, "Content-Uri")
2681 wkh_text_header(initiator_uri, "Initiator-Uri")
2682 wkh_text_header(profile, "Profile")
2683
2684 /*
2685  * Same for quoted-string value
2686  */
2687 #define wkh_quoted_string_header(underscored,Text) \
2688 static guint32 \
2689 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2690 { \
2691         wkh_0_Declarations; \
2692         gchar *str; \
2693         \
2694         wkh_1_WellKnownValue; \
2695                 /* Invalid */ \
2696         wkh_2_TextualValue; \
2697                 if (is_quoted_string(val_str[0])) { \
2698                         if (is_quoted_string(val_str[val_len-2])) { \
2699                                 /* Trailing quote - issue a warning */ \
2700                                 str = g_strdup_printf("%s" TrailingQuoteWarning, val_str); \
2701                         } else { /* OK (no trailing quote) */ \
2702                                 str = g_strdup_printf("%s\"", val_str); \
2703                         } \
2704                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2705                                         tvb, hdr_start, offset - hdr_start, str); \
2706                         g_free(str); \
2707                 } else { \
2708                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2709                                         tvb, hdr_start, offset - hdr_start, val_str); \
2710                         proto_item_append_text(ti, \
2711                                         " <Warning: should be encoded as a Quoted-string>"); \
2712                 } \
2713                 ok = TRUE; \
2714         wkh_3_ValueWithLength; \
2715                 /* Invalid */ \
2716         wkh_4_End(hf_hdr_ ## underscored); \
2717 }
2718
2719 wkh_quoted_string_header(content_id, "Content-ID")
2720
2721
2722 /*
2723  * Common code for headers with only a textual or a date value
2724  * is written in the macro below:
2725  */
2726 #define wkh_text_or_date_value_header(underscored,Text) \
2727 static guint32 \
2728 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2729 { \
2730         wkh_0_Declarations; \
2731         guint32 val = 0, off = val_start, len; \
2732         nstime_t tv; \
2733         gchar *str; /* may not be freed! */ \
2734         \
2735         wkh_1_WellKnownValue; \
2736                 /* Invalid */ \
2737         wkh_2_TextualValue; \
2738                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2739                                 tvb, hdr_start, offset - hdr_start, val_str); \
2740                 ok = TRUE; \
2741         wkh_3_ValueWithLength; \
2742                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
2743                         get_date_value(val, tvb, off, len, ok); \
2744                         if (ok) { \
2745                                 tv.secs = val; \
2746                                 tv.nsecs = 0; \
2747                                 str = abs_time_to_str(&tv); \
2748                                 g_assert(str); \
2749                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2750                                                 tvb, hdr_start, offset - hdr_start, str); \
2751                                 /* BEHOLD: do NOT try to free str, as this generates a core
2752                                  * dump!  It looks like abs_time_to_str() is buggy or works
2753                                  * with static data. */ \
2754                         } \
2755                 } \
2756         wkh_4_End(hf_hdr_ ## underscored); \
2757 }
2758
2759 /* If-Range */
2760 wkh_text_or_date_value_header(if_range,"If-Range")
2761
2762
2763 /*
2764  * Common code for headers with only a date value
2765  * is written in the macro below:
2766  */
2767 #define wkh_date_value_header(underscored,Text) \
2768 static guint32 \
2769 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2770 { \
2771         wkh_0_Declarations; \
2772         guint32 val = 0, off = val_start, len; \
2773         nstime_t tv; \
2774         gchar *str; /* may not be freed! */ \
2775         \
2776         wkh_1_WellKnownValue; \
2777                 /* Invalid */ \
2778         wkh_2_TextualValue; \
2779                 /* Invalid */ \
2780         wkh_3_ValueWithLength; \
2781                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
2782                         get_date_value(val, tvb, off, len, ok); \
2783                         if (ok) { \
2784                                 tv.secs = val; \
2785                                 tv.nsecs = 0; \
2786                                 str = abs_time_to_str(&tv); \
2787                                 g_assert(str); \
2788                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2789                                                 tvb, hdr_start, offset - hdr_start, str); \
2790                                 /* BEHOLD: do NOT try to free str, as this generates a core
2791                                  * dump!  It looks like abs_time_to_str() is buggy or works
2792                                  * with static data. */ \
2793                         } \
2794                 } \
2795         wkh_4_End(hf_hdr_ ## underscored); \
2796 }
2797
2798 /* Date-value only headers: */
2799 wkh_date_value_header(date, "Date")
2800 wkh_date_value_header(expires, "Expires")
2801 wkh_date_value_header(if_modified_since, "If-Modified-Since")
2802 wkh_date_value_header(if_unmodified_since, "If-Unmodified-Since")
2803 wkh_date_value_header(last_modified, "Last-Modified")
2804
2805
2806 /* Date-value with special interpretation of zero value */
2807 #define wkh_tod_value_header(underscored,Text) \
2808 static guint32 \
2809 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2810 { \
2811         wkh_0_Declarations; \
2812         guint32 val = 0, off = val_start, len; \
2813         nstime_t tv; \
2814         gchar *str; /* may not be freed! */ \
2815         \
2816         wkh_1_WellKnownValue; \
2817                 if (val_id == 0x80) { /* Openwave TOD header uses this format */ \
2818                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2819                                         tvb, hdr_start, offset - hdr_start, \
2820                                         "Requesting Time Of Day"); \
2821                         proto_item_append_text(ti, \
2822                                         " <Warning: should be encoded as long-integer>"); \
2823                         ok = TRUE; \
2824                 } \
2825                 /* It seems VERY unlikely that we'll see date values within the first \
2826                  * 127 seconds of the UNIX 1-1-1970 00:00:00 start of the date clocks \
2827                  * so I assume such a value is a genuine error */ \
2828         wkh_2_TextualValue; \
2829                 /* Invalid */ \
2830         wkh_3_ValueWithLength; \
2831                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
2832                         get_date_value(val, tvb, off, len, ok); \
2833                         if (ok) { \
2834                                 if (val == 0) { \
2835                                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2836                                                         tvb, hdr_start, offset - hdr_start, \
2837                                                         "Requesting Time Of Day"); \
2838                                 } else { \
2839                                         tv.secs = val; \
2840                                         tv.nsecs = 0; \
2841                                         str = abs_time_to_str(&tv); \
2842                                         g_assert(str); \
2843                                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2844                                                         tvb, hdr_start, offset - hdr_start, str); \
2845                                 } \
2846                         } \
2847                 } \
2848         wkh_4_End(hf_hdr_ ## underscored); \
2849 }
2850
2851 wkh_tod_value_header(x_wap_tod, "X-Wap-Tod")
2852
2853
2854 /*
2855  * Age-value: Delta-seconds-value
2856  */
2857 static guint32
2858 wkh_age(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
2859 {
2860         wkh_0_Declarations;
2861         guint32 val = 0, off = val_start, len;
2862
2863         wkh_1_WellKnownValue;
2864                 val = val_id & 0x7F;
2865                 val_str = g_strdup_printf("%u second%s", val, PLURALIZE(val));
2866                 ti = proto_tree_add_string(tree, hf_hdr_age,
2867                                 tvb, hdr_start, offset - hdr_start, val_str);
2868                 g_free(val_str); /* proto_XXX creates a copy */
2869                 ok = TRUE;
2870         wkh_2_TextualValue;
2871                 /* Invalid */
2872         wkh_3_ValueWithLength;
2873                 if (val_id <= 4) { /* Length field already parsed by macro! */
2874                         get_long_integer(val, tvb, off, len, ok);
2875                         if (ok) {
2876                                 val_str = g_strdup_printf("%u second%s", val, PLURALIZE(val));
2877                                 ti = proto_tree_add_string(tree, hf_hdr_age,
2878                                                 tvb, hdr_start, offset - hdr_start, val_str);
2879                                 g_free(val_str); /* proto_XXX creates a copy */
2880                         }
2881                 }
2882         wkh_4_End(hf_hdr_age);
2883 }
2884
2885
2886 /*
2887  * Template for Integer lookup or text value headers:
2888  */
2889 #define wkh_integer_lookup_or_text_value(underscored,Text,valueString,valueName) \
2890 static guint32 \
2891 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
2892 { \
2893         wkh_0_Declarations; \
2894         guint32 val = 0, off = val_start, len; \
2895         \
2896         wkh_1_WellKnownValue; \
2897                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2898                                 tvb, hdr_start, offset - hdr_start, \
2899                                 val_to_str(val_id & 0x7F, valueString, \
2900                                 "(Unknown " valueName " identifier 0x%X)")); \
2901                 ok = TRUE; \
2902         wkh_2_TextualValue; \
2903                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2904                                 tvb, hdr_start, offset - hdr_start, val_str); \
2905                 ok = TRUE; \
2906         wkh_3_ValueWithLength; \
2907                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
2908                         get_long_integer(val, tvb, off, len, ok); \
2909                         if (ok) { \
2910                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2911                                                 tvb, hdr_start, offset - hdr_start, \
2912                                                 val_to_str(val_id & 0x7F, valueString, \
2913                                                 "(Unknown " valueName " identifier 0x%X)")); \
2914                         } \
2915                 } \
2916         wkh_4_End(hf_hdr_ ## underscored); \
2917 }
2918
2919 /*
2920  * Wap-application-value: Uri-value | Integer-value
2921  */
2922 wkh_integer_lookup_or_text_value(x_wap_application_id, "X-Wap-Application-Id",
2923                 vals_wap_application_ids, "WAP application")
2924 wkh_integer_lookup_or_text_value(accept_application, "Accept-Application",
2925                 vals_wap_application_ids, "WAP application")
2926 wkh_integer_lookup_or_text_value(content_language, "Content-Language",
2927                 vals_languages, "language")
2928 /* NOTE - Although the WSP spec says this is an integer-value, the WSP headers
2929  * are encoded as a 7-bit entity! */
2930 wkh_integer_lookup_or_text_value(trailer, "Trailer",
2931                 vals_field_names, "well-known-header")
2932
2933
2934 /*
2935  * Challenge
2936  */
2937
2938 /*
2939  * Common code for headers with only a challenge value
2940  * is written in the macro below:
2941  */
2942 #define wkh_challenge_value_header(underscored,Text) \
2943 static guint32 \
2944 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, \
2945                 guint32 hdr_start) \
2946 { \
2947         wkh_0_Declarations; \
2948         guint8 peek; \
2949         guint32 off, len; \
2950         proto_tree *subtree; \
2951         gchar *str; \
2952         \
2953         wkh_1_WellKnownValue; \
2954                 /* Invalid */ \
2955         wkh_2_TextualValue; \
2956                 /* Invalid */ \
2957         wkh_3_ValueWithLength; \
2958                 off = val_start + val_len_len; \
2959                 peek = tvb_get_guint8(tvb, off); \
2960                 if (peek == 0x80) { /* Basic */ \
2961                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2962                                         tvb, hdr_start, offset - hdr_start, "basic"); \
2963                         subtree = proto_item_add_subtree(ti, ett_header); \
2964                         proto_tree_add_string(subtree, hf_hdr_ ## underscored ## _scheme, \
2965                                         tvb, off, 1, "basic"); \
2966                         off++; \
2967                         /* Realm: text-string */ \
2968                         get_text_string(str,tvb,off,len,ok); \
2969                         if (ok) { \
2970                                 proto_tree_add_string(subtree, \
2971                                                 hf_hdr_ ## underscored ## _realm, \
2972                                                 tvb, off, len, str); \
2973                                 val_str = g_strdup_printf("; realm=%s", str); \
2974                                 proto_item_append_string(ti, val_str); \
2975                                 g_free(val_str); \
2976                                 g_free(str); \
2977                                 off += len; \
2978                         } \
2979                 } else { /* Authentication-scheme: token-text */ \
2980                         get_token_text(str, tvb, off, len, ok); \
2981                         if (ok) { \
2982                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
2983                                                 tvb, hdr_start, off - hdr_start, str); \
2984                                 subtree = proto_item_add_subtree(ti, ett_header); \
2985                                 proto_tree_add_string(subtree, \
2986                                                 hf_hdr_ ## underscored ## _scheme, \
2987                                                 tvb, hdr_start, off - hdr_start, str); \
2988                                 g_free(str); \
2989                                 off += len; \
2990                                 /* Realm: text-string */ \
2991                                 get_text_string(str,tvb,off,len,ok); \
2992                                 if (ok) { \
2993                                         proto_tree_add_string(subtree, \
2994                                                         hf_hdr_ ## underscored ## _realm, \
2995                                                         tvb, off, len, str); \
2996                                         val_str = g_strdup_printf("; realm=%s", str); \
2997                                         proto_item_append_string(ti, val_str); \
2998                                         g_free(val_str); \
2999                                         g_free(str); \
3000                                         off += len; \
3001                                         /* Auth-params: parameter - TODO */ \
3002                                         while (off < offset) /* Parse parameters */ \
3003                                                 off = parameter(subtree, ti, tvb, off, offset - off); \
3004                                 } \
3005                         } \
3006                 } \
3007         wkh_4_End(hf_hdr_ ## underscored); \
3008 }
3009
3010 /* Challenge-value only headers: */
3011 wkh_challenge_value_header(www_authenticate, "WWW-Authenticate")
3012 wkh_challenge_value_header(proxy_authenticate, "Proxy-Authenticate")
3013
3014
3015 /*
3016  * Credentials
3017  */
3018
3019 /*
3020  * Common code for headers with only a credentials value
3021  * is written in the macro below:
3022  */
3023 #define wkh_credentials_value_header(underscored,Text) \
3024 static guint32 \
3025 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, \
3026                 guint32 hdr_start) \
3027 { \
3028         wkh_0_Declarations; \
3029         guint8 peek; \
3030         guint32 off, len; \
3031         proto_tree *subtree; \
3032         gchar *str; \
3033         \
3034         wkh_1_WellKnownValue; \
3035                 /* Invalid */ \
3036         wkh_2_TextualValue; \
3037                 /* Invalid */ \
3038         wkh_3_ValueWithLength; \
3039                 off = val_start + val_len_len; \
3040                 peek = tvb_get_guint8(tvb, off); \
3041                 if (peek == 0x80) { /* Basic */ \
3042                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3043                                         tvb, hdr_start, offset - hdr_start, "basic"); \
3044                         subtree = proto_item_add_subtree(ti, ett_header); \
3045                         proto_tree_add_string(subtree, hf_hdr_ ## underscored ## _scheme, \
3046                                         tvb, off, 1, "basic"); \
3047                         off++; \
3048                         /* User-id: text-string */ \
3049                         get_text_string(str,tvb,off,len,ok); \
3050                         if (ok) { \
3051                                 proto_tree_add_string(subtree, \
3052                                                 hf_hdr_ ## underscored ## _user_id, \
3053                                                 tvb, off, len, str); \
3054                                 val_str = g_strdup_printf("; user-id=%s", str); \
3055                                 proto_item_append_string(ti, val_str); \
3056                                 g_free(val_str); \
3057                                 g_free(str); \
3058                                 off += len; \
3059                                 /* Password: text-string */ \
3060                                 get_text_string(str,tvb,off,len,ok); \
3061                                 if (ok) { \
3062                                         proto_tree_add_string(subtree, \
3063                                                         hf_hdr_ ## underscored ## _password, \
3064                                                         tvb, off, len, str); \
3065                                         val_str = g_strdup_printf("; password=%s", str); \
3066                                         proto_item_append_string(ti, val_str); \
3067                                         g_free(val_str); \
3068                                         g_free(str); \
3069                                         off += len; \
3070                                 } \
3071                         } \
3072                 } else { /* Authentication-scheme: token-text */ \
3073                         get_token_text(str, tvb, off, len, ok); \
3074                         if (ok) { \
3075                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3076                                                 tvb, hdr_start, off - hdr_start, str); \
3077                                 subtree = proto_item_add_subtree(ti, ett_header); \
3078                                 proto_tree_add_string(subtree, \
3079                                                 hf_hdr_ ## underscored ## _scheme, \
3080                                                 tvb, hdr_start, off - hdr_start, str); \
3081                                 g_free(str); \
3082                                 off += len; \
3083                                 /* Auth-params: parameter - TODO */ \
3084                                 while (off < offset) /* Parse parameters */ \
3085                                         off = parameter(subtree, ti, tvb, off, offset - off); \
3086                         } \
3087                 } \
3088         wkh_4_End(hf_hdr_ ## underscored); \
3089 }
3090
3091 /* Credentials-value only headers: */
3092 wkh_credentials_value_header(authorization, "Authorization")
3093 wkh_credentials_value_header(proxy_authorization, "Proxy-Authorization")
3094
3095
3096 /*
3097  * Content-md5-value = 16*16 OCTET
3098  */
3099 static guint32
3100 wkh_content_md5 (proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3101 {
3102         wkh_0_Declarations;
3103         guint32 off;
3104
3105         wkh_1_WellKnownValue;
3106                 /* Invalid */
3107         wkh_2_TextualValue;
3108                 /* Invalid */
3109         wkh_3_ValueWithLength;
3110                 off = val_start + val_len_len;
3111                 if (val_len == 16) {
3112                         val_str = g_strdup_printf(
3113                                         "%02x%02x%02x%02x%02x%02x%02x%02x"
3114                                         "%02x%02x%02x%02x%02x%02x%02x%02x",
3115                                         tvb_get_guint8(tvb, off),
3116                                         tvb_get_guint8(tvb, off + 1),
3117                                         tvb_get_guint8(tvb, off + 2),
3118                                         tvb_get_guint8(tvb, off + 3),
3119                                         tvb_get_guint8(tvb, off + 4),
3120                                         tvb_get_guint8(tvb, off + 5),
3121                                         tvb_get_guint8(tvb, off + 6),
3122                                         tvb_get_guint8(tvb, off + 7),
3123                                         tvb_get_guint8(tvb, off + 8),
3124                                         tvb_get_guint8(tvb, off + 9),
3125                                         tvb_get_guint8(tvb, off + 10),
3126                                         tvb_get_guint8(tvb, off + 11),
3127                                         tvb_get_guint8(tvb, off + 12),
3128                                         tvb_get_guint8(tvb, off + 13),
3129                                         tvb_get_guint8(tvb, off + 14),
3130                                         tvb_get_guint8(tvb, off + 15)
3131                         );
3132                         ti = proto_tree_add_string(tree, hf_hdr_content_md5,
3133                                         tvb, hdr_start, offset - hdr_start, val_str);
3134                         g_free(val_str);
3135                         ok = TRUE;
3136                 }
3137         wkh_4_End(hf_hdr_content_md5);
3138 }
3139
3140
3141 /*
3142  * Pragma-value = 0x80 | Length Parameter
3143  */
3144 static guint32
3145 wkh_pragma(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3146 {
3147         wkh_0_Declarations;
3148         guint32 off;
3149
3150         wkh_1_WellKnownValue;
3151                 if (val_id == 0x80) {
3152                         ti = proto_tree_add_string(tree, hf_hdr_pragma,
3153                                         tvb, hdr_start, offset - hdr_start, "no-cache");
3154                         ok = TRUE;
3155                 }
3156         wkh_2_TextualValue;
3157                 /* Invalid */
3158         wkh_3_ValueWithLength;
3159                 off = val_start + val_len_len;
3160                 ti = proto_tree_add_string(tree, hf_hdr_pragma,
3161                                 tvb, hdr_start, off - hdr_start, "");
3162                 /* NULL subtree for parameter() results in no subtree
3163                  * TODO - provide a single parameter dissector that appends data
3164                  * to the header field data. */
3165                 off = parameter(NULL, ti, tvb, off, offset - off);
3166                 ok = TRUE;
3167         wkh_4_End(hf_hdr_pragma);
3168 }
3169
3170
3171 /*
3172  * Integer-value
3173  */
3174 #define wkh_integer_value_header(underscored,Text) \
3175 static guint32 \
3176 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
3177 { \
3178         wkh_0_Declarations; \
3179         guint32 val = 0, off = val_start, len; \
3180         gchar *str; /* may not be freed! */ \
3181         \
3182         wkh_1_WellKnownValue; \
3183                 str = g_strdup_printf("%u", val_id & 0x7F); \
3184                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3185                                 tvb, hdr_start, offset - hdr_start, str); \
3186                 g_free(str); \
3187                 ok = TRUE; \
3188         wkh_2_TextualValue; \
3189                 /* Invalid */ \
3190         wkh_3_ValueWithLength; \
3191                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
3192                         get_long_integer(val, tvb, off, len, ok); \
3193                         if (ok) { \
3194                                 str = g_strdup_printf("%u", val); \
3195                                 ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3196                                                 tvb, hdr_start, offset - hdr_start, str); \
3197                                 g_free(str); \
3198                         } \
3199                 } \
3200         wkh_4_End(hf_hdr_ ## underscored); \
3201 }
3202
3203 wkh_integer_value_header(content_length, "Content-Length")
3204 wkh_integer_value_header(max_forwards, "Max-Forwards")
3205
3206
3207 #define wkh_integer_lookup_value_header(underscored,Text,valueString,valueName) \
3208 static guint32 \
3209 wkh_ ## underscored(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start) \
3210 { \
3211         wkh_0_Declarations; \
3212         guint32 val = 0, off = val_start, len; \
3213         \
3214         wkh_1_WellKnownValue; \
3215                 val_str = match_strval(val_id & 0x7F, valueString); \
3216                 if (val_str) { \
3217                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3218                                 tvb, hdr_start, offset - hdr_start, val_str); \
3219                         ok = TRUE; \
3220                 } else { \
3221                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3222                                 tvb, hdr_start, offset - hdr_start, \
3223                                 "<Unknown " valueName ">"); \
3224                 } \
3225         wkh_2_TextualValue; \
3226                 /* Invalid */ \
3227         wkh_3_ValueWithLength; \
3228                 if (val_id <= 4) { /* Length field already parsed by macro! */ \
3229                         get_long_integer(val, tvb, off, len, ok); \
3230                         if (ok) { \
3231                                 val_str = match_strval(val_id & 0x7F, valueString); \
3232                                 if (val_str) { \
3233                                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3234                                                 tvb, hdr_start, offset - hdr_start, val_str); \
3235                                         ok = TRUE; \
3236                                 } else { \
3237                                         ti = proto_tree_add_string(tree, hf_hdr_ ## underscored, \
3238                                                 tvb, hdr_start, offset - hdr_start, \
3239                                                 "<Unknown " valueName ">"); \
3240                                 } \
3241                         } \
3242                 } \
3243         wkh_4_End(hf_hdr_ ## underscored); \
3244 }
3245
3246 wkh_integer_lookup_value_header(bearer_indication, "Bearer-Indication",
3247                 vals_bearer_types, "bearer type")
3248
3249
3250 /*
3251  * Cache-control-value
3252  */
3253 static guint32
3254 wkh_cache_control(proto_tree *tree, tvbuff_t *tvb, guint32 hdr_start)
3255 {
3256         wkh_0_Declarations;
3257         guint32 off, len, val = 0;
3258         guint8 peek, cache_control_directive;
3259         gchar *str;
3260
3261         wkh_1_WellKnownValue;
3262                 val = val_id & 0x7F;
3263                 val_str = match_strval(val, vals_cache_control);
3264                 if (val_str) {
3265                         ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3266                                         tvb, hdr_start, offset - hdr_start, val_str);
3267                         ok = TRUE;
3268                 }
3269         wkh_2_TextualValue;
3270                 ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3271                                 tvb, hdr_start, offset - hdr_start, val_str);
3272                 ok = TRUE;
3273         wkh_3_ValueWithLength;
3274                 /* General form:
3275                  *        ( no-cache | private ) 1*( Field-name )
3276                  *      | ( max-age | max-stale | min-fresh | s-maxage) Delta-seconds-value
3277                  *      | Token-text ( Integer-value | Text-value )
3278                  * Where:
3279                  *      Field-name = Short-integer | Token-text
3280                  */
3281                 off = val_start + val_len_len;
3282                 cache_control_directive = tvb_get_guint8(tvb, off++);
3283                 if (cache_control_directive & 0x80) { /* Well known cache directive */
3284                         switch (cache_control_directive & 0x7F) {
3285                                 case CACHE_CONTROL_NO_CACHE:
3286                                 case CACHE_CONTROL_PRIVATE:
3287                                         ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3288                                                         tvb, hdr_start, offset - hdr_start,
3289                                                         val_to_str (cache_control_directive & 0x7F, vals_cache_control,
3290                                                                 "<Unknown cache control directive 0x%02X>"));
3291                                         /* TODO: split multiple entries */
3292                                         while (ok && (off < offset)) { /* 1*( Field-name ) */
3293                                                 ok = TRUE;
3294                                                 peek = tvb_get_guint8(tvb, off);
3295                                                 if (peek & 0x80) { /* Well-known-field-name */
3296                                                         proto_item_append_string(ti,
3297                                                                         val_to_str (peek, vals_field_names,
3298                                                                                 "<Unknown WSP header field 0x%02X>"));
3299                                                         off++;
3300                                                 } else { /* Token-text */
3301                                                         get_token_text(val_str, tvb, off, len, ok);
3302                                                         if (ok) {
3303                                                                 proto_item_append_string(ti, val_str);
3304                                                                 g_free(val_str);
3305                                                                 off += len;
3306                                                         }
3307                                                 }
3308                                         }
3309                                         break;
3310
3311                                 case CACHE_CONTROL_MAX_AGE:
3312                                 case CACHE_CONTROL_MAX_STALE:
3313                                 case CACHE_CONTROL_MIN_FRESH:
3314                                 case CACHE_CONTROL_S_MAXAGE:
3315                                         ti = proto_tree_add_string(tree, hf_hdr_cache_control,
3316                                                         tvb, hdr_start, offset - hdr_start,
3317                                                         val_to_str (cache_control_directive & 0x7F, vals_cache_control,
3318                                                                 "<Unknown cache control directive 0x%02X>"));
3319                                         get_delta_seconds_value(val, tvb, off, len, ok);
3320                                         if (ok) {
3321                                                 val_str = g_strdup_printf("=%u second%s",
3322                                                                 val, PLURALIZE(val));
3323                                                 proto_item_append_string(ti, val_str);
3324                                                 g_free(val_str); /* proto_XXX creates a copy */
3325                                         }
3326                                         break;
3327
3328                                 default:
3329                                         /* ok = FALSE */
3330                                         break;
3331                   &nbs