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