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