Attach a descriptive name field type and base to dissector tables; that
[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.49 2001/12/08 06:41:42 guy 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  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  * 
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
39 #endif
40
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
43 #endif
44
45 #ifdef NEED_SNPRINTF_H
46 # ifdef HAVE_STDARG_H
47 #  include <stdarg.h>
48 # else
49 #  include <varargs.h>
50 # endif
51 # include "snprintf.h"
52 #endif
53
54 #include <string.h>
55 #include <glib.h>
56 #include "packet.h"
57 #include "ipv6-utils.h"
58 #include "conversation.h"
59 #include "packet-wap.h"
60 #include "packet-wsp.h"
61
62 /* File scoped variables for the protocol and registered fields */
63 static int proto_wsp                                    = HF_EMPTY;
64
65 /* These fields used by fixed part of header */
66 static int hf_wsp_header_tid                            = HF_EMPTY;
67 static int hf_wsp_header_pdu_type                       = HF_EMPTY;
68 static int hf_wsp_version_major                         = HF_EMPTY;
69 static int hf_wsp_version_minor                         = HF_EMPTY;
70 static int hf_wsp_capability_length                     = HF_EMPTY;
71 static int hf_wsp_capabilities_section                  = HF_EMPTY;
72 static int hf_wsp_capabilities_client_SDU               = HF_EMPTY;
73 static int hf_wsp_capabilities_server_SDU               = HF_EMPTY;
74 static int hf_wsp_capabilities_protocol_opt             = HF_EMPTY;
75 static int hf_wsp_capabilities_method_MOR               = HF_EMPTY;
76 static int hf_wsp_capabilities_push_MOR                 = HF_EMPTY;
77 static int hf_wsp_capabilities_extended_methods         = HF_EMPTY;
78 static int hf_wsp_capabilities_header_code_pages        = HF_EMPTY;
79 static int hf_wsp_capabilities_aliases                  = HF_EMPTY;
80 static int hf_wsp_header_uri_len                        = HF_EMPTY;
81 static int hf_wsp_header_uri                            = HF_EMPTY;
82 static int hf_wsp_server_session_id                     = HF_EMPTY;
83 static int hf_wsp_header_status                         = HF_EMPTY;
84 static int hf_wsp_header_length                         = HF_EMPTY;
85 static int hf_wsp_headers_section                       = HF_EMPTY;
86 static int hf_wsp_header                                = HF_EMPTY;
87 static int hf_wsp_content_type                          = HF_EMPTY;
88 static int hf_wsp_content_type_str                      = HF_EMPTY;
89 static int hf_wsp_parameter_well_known_charset          = HF_EMPTY;
90 static int hf_wsp_parameter_type                        = HF_EMPTY;
91 static int hf_wsp_parameter_name                        = HF_EMPTY;
92 static int hf_wsp_parameter_filename                    = HF_EMPTY;
93 static int hf_wsp_parameter_start                       = HF_EMPTY;
94 static int hf_wsp_parameter_start_info                  = HF_EMPTY;
95 static int hf_wsp_parameter_comment                     = HF_EMPTY;
96 static int hf_wsp_parameter_domain                      = HF_EMPTY;
97 static int hf_wsp_parameter_path                        = HF_EMPTY;
98 static int hf_wsp_parameter_upart_type                  = HF_EMPTY;
99 static int hf_wsp_parameter_upart_type_value            = HF_EMPTY;
100 static int hf_wsp_reply_data                            = HF_EMPTY;
101 static int hf_wsp_post_data                             = HF_EMPTY;
102 static int hf_wsp_push_data                             = HF_EMPTY;
103 static int hf_wsp_multipart_data                        = HF_EMPTY;
104 static int hf_wsp_mpart                                 = HF_EMPTY;
105
106 static int hf_wsp_header_shift_code                     = HF_EMPTY;
107 static int hf_wsp_header_accept                         = HF_EMPTY;
108 static int hf_wsp_header_accept_str                     = HF_EMPTY;
109 static int hf_wsp_header_accept_application             = HF_EMPTY;
110 static int hf_wsp_header_accept_application_str         = HF_EMPTY;
111 static int hf_wsp_header_accept_charset                 = HF_EMPTY;
112 static int hf_wsp_header_accept_charset_str             = HF_EMPTY;
113 static int hf_wsp_header_accept_language                = HF_EMPTY;
114 static int hf_wsp_header_accept_language_str            = HF_EMPTY;
115 static int hf_wsp_header_accept_ranges                  = HF_EMPTY;
116 static int hf_wsp_header_accept_ranges_str              = HF_EMPTY;
117 static int hf_wsp_header_cache_control                  = HF_EMPTY;
118 static int hf_wsp_header_cache_control_str              = HF_EMPTY;
119 static int hf_wsp_header_cache_control_field_name       = HF_EMPTY;
120 static int hf_wsp_header_connection                     = HF_EMPTY;
121 static int hf_wsp_header_connection_str                 = HF_EMPTY;
122 static int hf_wsp_header_cache_control_field_name_str   = HF_EMPTY;
123 static int hf_wsp_header_content_length                 = HF_EMPTY;
124 static int hf_wsp_header_age                            = HF_EMPTY;
125 static int hf_wsp_header_bearer_indication              = HF_EMPTY;
126 static int hf_wsp_header_date                           = HF_EMPTY;
127 static int hf_wsp_header_etag                           = HF_EMPTY;
128 static int hf_wsp_header_expires                        = HF_EMPTY;
129 static int hf_wsp_header_last_modified                  = HF_EMPTY;
130 static int hf_wsp_header_location                       = HF_EMPTY;
131 static int hf_wsp_header_if_modified_since              = HF_EMPTY;
132 static int hf_wsp_header_profile                        = HF_EMPTY;
133 static int hf_wsp_header_pragma                         = HF_EMPTY;
134 static int hf_wsp_header_server                         = HF_EMPTY;
135 static int hf_wsp_header_user_agent                     = HF_EMPTY;
136 static int hf_wsp_header_warning                        = HF_EMPTY;
137 static int hf_wsp_header_warning_code                   = HF_EMPTY;
138 static int hf_wsp_header_warning_agent                  = HF_EMPTY;
139 static int hf_wsp_header_warning_text                   = HF_EMPTY;
140 static int hf_wsp_header_application_header             = HF_EMPTY;
141 static int hf_wsp_header_application_value              = HF_EMPTY;
142 static int hf_wsp_header_x_wap_tod                      = HF_EMPTY;
143 static int hf_wsp_header_content_ID                     = HF_EMPTY;
144 static int hf_wsp_header_transfer_encoding              = HF_EMPTY;
145 static int hf_wsp_header_transfer_encoding_str          = HF_EMPTY;
146 static int hf_wsp_header_via                            = HF_EMPTY;
147 static int hf_wsp_header_wap_application_id             = HF_EMPTY;
148 static int hf_wsp_header_wap_application_id_str         = HF_EMPTY;
149
150 static int hf_wsp_redirect_flags                        = HF_EMPTY;
151 static int hf_wsp_redirect_permanent                    = HF_EMPTY;
152 static int hf_wsp_redirect_reuse_security_session       = HF_EMPTY;
153 static int hf_wsp_redirect_afl                          = HF_EMPTY;
154 static int hf_wsp_redirect_afl_bearer_type_included     = HF_EMPTY;
155 static int hf_wsp_redirect_afl_port_number_included     = HF_EMPTY;
156 static int hf_wsp_redirect_afl_address_len              = HF_EMPTY;
157 static int hf_wsp_redirect_bearer_type                  = HF_EMPTY;
158 static int hf_wsp_redirect_port_num                     = HF_EMPTY;
159 static int hf_wsp_redirect_ipv4_addr                    = HF_EMPTY;
160 static int hf_wsp_redirect_ipv6_addr                    = HF_EMPTY;
161 static int hf_wsp_redirect_addr                         = HF_EMPTY;
162
163 /* Initialize the subtree pointers */
164 static gint ett_wsp                                     = ETT_EMPTY;
165 static gint ett_content_type_parameters                 = ETT_EMPTY;
166 static gint ett_header                                  = ETT_EMPTY;
167 static gint ett_headers                                 = ETT_EMPTY;
168 static gint ett_header_warning                          = ETT_EMPTY;
169 static gint ett_header_cache_control_parameters         = ETT_EMPTY;
170 static gint ett_header_cache_control_field_names        = ETT_EMPTY;
171 static gint ett_capabilities                            = ETT_EMPTY;
172 static gint ett_content_type                            = ETT_EMPTY;
173 static gint ett_redirect_flags                          = ETT_EMPTY;
174 static gint ett_redirect_afl                            = ETT_EMPTY;
175 static gint ett_multiparts                              = ETT_EMPTY;
176 static gint ett_mpartlist                               = ETT_EMPTY;
177
178 /* Handle for WSP-over-UDP dissector */
179 static dissector_handle_t wsp_fromudp_handle;
180
181 /* Handle for WTP-over-UDP dissector */
182 static dissector_handle_t wtp_fromudp_handle;
183
184 /* Handle for WMLC dissector */
185 static dissector_handle_t wmlc_handle;
186
187 static const value_string vals_pdu_type[] = {
188         { 0x00, "Reserved" },
189         { 0x01, "Connect" },
190         { 0x02, "ConnectReply" },
191         { 0x03, "Redirect" },
192         { 0x04, "Reply" },
193         { 0x05, "Disconnect" },
194         { 0x06, "Push" },
195         { 0x07, "ConfirmedPush" },
196         { 0x08, "Suspend" },
197         { 0x09, "Resume" },
198
199         /* 0x10 - 0x3F Unassigned */
200
201         { 0x40, "Get" },
202         { 0x41, "Options" },
203         { 0x42, "Head" },
204         { 0x43, "Delete" },
205         { 0x44, "Trace" },
206
207         /* 0x45 - 0x4F Unassigned (Get PDU) */
208         /* 0x50 - 0x5F Extended method (Get PDU) */
209
210         { 0x60, "Post" },
211         { 0x61, "Put" },
212
213         /* 0x62 - 0x6F Unassigned (Post PDU) */
214         /* 0x70 - 0x7F Extended method (Post PDU) */
215         /* 0x80 - 0xFF Reserved */
216
217         { 0x00, NULL }
218
219 };
220
221 static const value_string vals_status[] = {
222         /* 0x00 - 0x0F Reserved */
223
224         { 0x10, "Continue" },
225         { 0x11, "Switching Protocols" },
226
227         { 0x20, "OK" },
228         { 0x21, "Created" },
229         { 0x22, "Accepted" },
230         { 0x23, "Non-Authoritative Information" },
231         { 0x24, "No Content" },
232         { 0x25, "Reset Content" },
233         { 0x26, "Partial Content" },
234
235         { 0x30, "Multiple Choices" },
236         { 0x31, "Moved Permanently" },
237         { 0x32, "Moved Temporarily" },
238         { 0x33, "See Other" },
239         { 0x34, "Not Modified" },
240         { 0x35, "Use Proxy" },
241         { 0x37, "Temporary Redirect" },
242
243         { 0x40, "Bad Request" },
244         { 0x41, "Unauthorised" },
245         { 0x42, "Payment Required" },
246         { 0x43, "Forbidden" },
247         { 0x44, "Not Found" },
248         { 0x45, "Method Not Allowed" },
249         { 0x46, "Not Acceptable" },
250         { 0x47, "Proxy Authentication Required" },
251         { 0x48, "Request Timeout" },
252         { 0x49, "Conflict" },
253         { 0x4A, "Gone" },
254         { 0x4B, "Length Required" },
255         { 0x4C, "Precondition Failed" },
256         { 0x4D, "Request Entity Too Large" },
257         { 0x4E, "Request-URI Too Large" },
258         { 0x4F, "Unsupported Media Type" },
259         { 0x50, "Requested Range Not Satisfiable" },
260         { 0x51, "Expectation Failed" },
261
262         { 0x60, "Internal Server Error" },
263         { 0x61, "Not Implemented" },
264         { 0x62, "Bad Gateway" },
265         { 0x63, "Service Unavailable" },
266         { 0x64, "Gateway Timeout" },
267         { 0x65, "HTTP Version Not Supported" },
268         { 0x00, NULL }
269 };
270
271 /*
272  * Field names.
273  */
274 #define FN_ACCEPT               0x00
275 #define FN_ACCEPT_CHARSET_DEP   0x01    /* encoding version 1.1, deprecated */
276 #define FN_ACCEPT_ENCODING_DEP  0x02    /* encoding version 1.1, deprecated */
277 #define FN_ACCEPT_LANGUAGE      0x03
278 #define FN_ACCEPT_RANGES        0x04
279 #define FN_AGE                  0x05
280 #define FN_ALLOW                0x06
281 #define FN_AUTHORIZATION        0x07
282 #define FN_CACHE_CONTROL_DEP    0x08    /* encoding version 1.1, deprecated */
283 #define FN_CONNECTION           0x09
284 #define FN_CONTENT_BASE         0x0A
285 #define FN_CONTENT_ENCODING     0x0B
286 #define FN_CONTENT_LANGUAGE     0x0C
287 #define FN_CONTENT_LENGTH       0x0D
288 #define FN_CONTENT_LOCATION     0x0E
289 #define FN_CONTENT_MD5          0x0F
290 #define FN_CONTENT_RANGE_DEP    0x10    /* encoding version 1.1, deprecated */
291 #define FN_CONTENT_TYPE         0x11
292 #define FN_DATE                 0x12
293 #define FN_ETAG                 0x13
294 #define FN_EXPIRES              0x14
295 #define FN_FROM                 0x15
296 #define FN_HOST                 0x16
297 #define FN_IF_MODIFIED_SINCE    0x17
298 #define FN_IF_MATCH             0x18
299 #define FN_IF_NONE_MATCH        0x19
300 #define FN_IF_RANGE             0x1A
301 #define FN_IF_UNMODIFIED_SINCE  0x1B
302 #define FN_LOCATION             0x1C
303 #define FN_LAST_MODIFIED        0x1D
304 #define FN_MAX_FORWARDS         0x1E
305 #define FN_PRAGMA               0x1F
306 #define FN_PROXY_AUTHENTICATE   0x20
307 #define FN_PROXY_AUTHORIZATION  0x21
308 #define FN_PUBLIC               0x22
309 #define FN_RANGE                0x23
310 #define FN_REFERER              0x24
311 #define FN_RETRY_AFTER          0x25
312 #define FN_SERVER               0x26
313 #define FN_TRANSFER_ENCODING    0x27
314 #define FN_UPGRADE              0x28
315 #define FN_USER_AGENT           0x29
316 #define FN_VARY                 0x2A
317 #define FN_VIA                  0x2B
318 #define FN_WARNING              0x2C
319 #define FN_WWW_AUTHENTICATE     0x2D
320 #define FN_CONTENT_DISPOSITION  0x2E
321 #define FN_X_WAP_APPLICATION_ID 0x2F
322 #define FN_X_WAP_CONTENT_URI    0x30
323 #define FN_X_WAP_INITIATOR_URI  0x31
324 #define FN_ACCEPT_APPLICATION   0x32
325 #define FN_BEARER_INDICATION    0x33
326 #define FN_PUSH_FLAG            0x34
327 #define FN_PROFILE              0x35
328 #define FN_PROFILE_DIFF         0x36
329 #define FN_PROFILE_WARNING      0x37
330 #define FN_EXPECT               0x38
331 #define FN_TE                   0x39
332 #define FN_TRAILER              0x3A
333 #define FN_ACCEPT_CHARSET       0x3B    /* encoding version 1.3 */
334 #define FN_ACCEPT_ENCODING      0x3C    /* encoding version 1.3 */
335 #define FN_CACHE_CONTROL        0x3D    /* encoding version 1.3 */
336 #define FN_CONTENT_RANGE        0x3E    /* encoding version 1.3 */
337 #define FN_X_WAP_TOD            0x3F
338 #define FN_CONTENT_ID           0x40
339 #define FN_SET_COOKIE           0x41
340 #define FN_COOKIE               0x42
341 #define FN_ENCODING_VERSION     0x43
342 #define FN_PROFILE_WARNING14    0x44    /* encoding version 1.4 */
343 #define FN_CONTENT_DISPOSITION14        0x45    /* encoding version 1.4 */
344 #define FN_X_WAP_SECURITY       0x46
345 #define FN_CACHE_CONTROL14      0x47    /* encoding version 1.4 */
346
347 static const value_string vals_field_names[] = {
348         { FN_ACCEPT,               "Accept" },
349         { FN_ACCEPT_CHARSET_DEP,   "Accept-Charset (encoding 1.1)" },
350         { FN_ACCEPT_ENCODING_DEP,  "Accept-Encoding (encoding 1.1)" },
351         { FN_ACCEPT_LANGUAGE,      "Accept-Language" },
352         { FN_ACCEPT_RANGES,        "Accept-Ranges" },
353         { FN_AGE,                  "Age" },
354         { FN_ALLOW,                "Allow" },
355         { FN_AUTHORIZATION,        "Authorization" },
356         { FN_CACHE_CONTROL_DEP,    "Cache-Control (encoding 1.1)" },
357         { FN_CONNECTION,           "Connection" },
358         { FN_CONTENT_BASE,         "Content-Base" },
359         { FN_CONTENT_ENCODING,     "Content-Encoding" },
360         { FN_CONTENT_LANGUAGE,     "Content-Language" },
361         { FN_CONTENT_LENGTH,       "Content-Length" },
362         { FN_CONTENT_LOCATION,     "Content-Location" },
363         { FN_CONTENT_MD5,          "Content-MD5" },
364         { FN_CONTENT_RANGE_DEP,    "Content-Range (encoding 1.1)" },
365         { FN_CONTENT_TYPE,         "Content-Type" },
366         { FN_DATE,                 "Date" },
367         { FN_ETAG,                 "Etag" },
368         { FN_EXPIRES,              "Expires" },
369         { FN_FROM,                 "From" },
370         { FN_HOST,                 "Host" },
371         { FN_IF_MODIFIED_SINCE,    "If-Modified-Since" },
372         { FN_IF_MATCH,             "If-Match" },
373         { FN_IF_NONE_MATCH,        "If-None-Match" },
374         { FN_IF_RANGE,             "If-Range" },
375         { FN_IF_UNMODIFIED_SINCE,  "If-Unmodified-Since" },
376         { FN_LOCATION,             "Location" },
377         { FN_LAST_MODIFIED,        "Last-Modified" },
378         { FN_MAX_FORWARDS,         "Max-Forwards" },
379         { FN_PRAGMA,               "Pragma" },
380         { FN_PROXY_AUTHENTICATE,   "Proxy-Authenticate" },
381         { FN_PROXY_AUTHORIZATION,  "Proxy-Authorization" },
382         { FN_PUBLIC,               "Public" },
383         { FN_RANGE,                "Range" },
384         { FN_REFERER,              "Referer" },
385         { FN_RETRY_AFTER,          "Retry-After" },
386         { FN_SERVER,               "Server" },
387         { FN_TRANSFER_ENCODING,    "Transfer-Encoding" },
388         { FN_UPGRADE,              "Upgrade" },
389         { FN_USER_AGENT,           "User-Agent" },
390         { FN_VARY,                 "Vary" },
391         { FN_VIA,                  "Via" },
392         { FN_WARNING,              "Warning" },
393         { FN_WWW_AUTHENTICATE,     "WWW-Authenticate" },
394         { FN_CONTENT_DISPOSITION,  "Content-Disposition" },
395         { FN_X_WAP_APPLICATION_ID, "X-Wap-Application-ID" },
396         { FN_X_WAP_CONTENT_URI,    "X-Wap-Content-URI" },
397         { FN_X_WAP_INITIATOR_URI,  "X-Wap-Initiator-URI" },
398         { FN_ACCEPT_APPLICATION,   "Accept-Application" },
399         { FN_BEARER_INDICATION,    "Bearer-Indication" },
400         { FN_PUSH_FLAG,            "Push-Flag" },
401         { FN_PROFILE,              "Profile" },
402         { FN_PROFILE_DIFF,         "Profile-Diff" },
403         { FN_PROFILE_WARNING,      "Profile-Warning" },
404         { FN_EXPECT,               "Expect" },
405         { FN_TE,                   "TE" },
406         { FN_TRAILER,              "Trailer" },
407         { FN_ACCEPT_CHARSET,       "Accept-Charset" },
408         { FN_ACCEPT_ENCODING,      "Accept-Encoding" },
409         { FN_CACHE_CONTROL,        "Cache-Control" },
410         { FN_CONTENT_RANGE,        "Content-Range" },
411         { FN_X_WAP_TOD,            "X-Wap-Tod" },
412         { FN_CONTENT_ID,           "Content-ID" },
413         { FN_SET_COOKIE,           "Set-Cookie" },
414         { FN_COOKIE,               "Cookie" },
415         { FN_ENCODING_VERSION,     "Encoding-Version" },
416         { FN_PROFILE_WARNING14,    "Profile-Warning (encoding 1.4)" },
417         { FN_CONTENT_DISPOSITION14,"Content-Disposition (encoding 1.4)" },
418         { FN_X_WAP_SECURITY,       "X-WAP-Security" },
419         { FN_CACHE_CONTROL14,      "Cache-Control (encoding 1.4)" },
420         { 0,                       NULL }
421 };      
422
423 /*
424  * Bearer types (from the WDP specification).
425  */
426 #define BT_IPv4                 0x00
427 #define BT_IPv6                 0x01
428 #define BT_GSM_USSD             0x02
429 #define BT_GSM_SMS              0x03
430 #define BT_ANSI_136_GUTS        0x04
431 #define BT_IS_95_SMS            0x05
432 #define BT_IS_95_CSD            0x06
433 #define BT_IS_95_PACKET_DATA    0x07
434 #define BT_ANSI_136_CSD         0x08
435 #define BT_ANSI_136_PACKET_DATA 0x09
436 #define BT_GSM_CSD              0x0A
437 #define BT_GSM_GPRS             0x0B
438 #define BT_GSM_USSD_IPv4        0x0C
439 #define BT_AMPS_CDPD            0x0D
440 #define BT_PDC_CSD              0x0E
441 #define BT_PDC_PACKET_DATA      0x0F
442 #define BT_IDEN_SMS             0x10
443 #define BT_IDEN_CSD             0x11
444 #define BT_IDEN_PACKET_DATA     0x12
445 #define BT_PAGING_FLEX          0x13
446 #define BT_PHS_SMS              0x14
447 #define BT_PHS_CSD              0x15
448 #define BT_GSM_USSD_GSM_SC      0x16
449 #define BT_TETRA_SDS_ITSI       0x17
450 #define BT_TETRA_SDS_MSISDN     0x18
451 #define BT_TETRA_PACKET_DATA    0x19
452 #define BT_PAGING_REFLEX        0x1A
453 #define BT_GSM_USSD_MSISDN      0x1B
454 #define BT_MOBITEX_MPAK         0x1C
455 #define BT_ANSI_136_GHOST       0x1D
456
457 static const value_string vals_bearer_types[] = {
458         { BT_IPv4,                 "IPv4" },
459         { BT_IPv6,                 "IPv6" },
460         { BT_GSM_USSD,             "GSM USSD" },
461         { BT_GSM_SMS,              "GSM SMS" },
462         { BT_ANSI_136_GUTS,        "ANSI-136 GUTS/R-Data" },
463         { BT_IS_95_SMS,            "IS-95 CDMA SMS" },
464         { BT_IS_95_CSD,            "IS-95 CDMA CSD" },
465         { BT_IS_95_PACKET_DATA,    "IS-95 CDMA Packet data" },
466         { BT_ANSI_136_CSD,         "ANSI-136 CSD" },
467         { BT_ANSI_136_PACKET_DATA, "ANSI-136 Packet data" },
468         { BT_GSM_CSD,              "GSM CSD" },
469         { BT_GSM_GPRS,             "GSM GPRS" },
470         { BT_GSM_USSD_IPv4,        "GSM USSD (IPv4 addresses)" },
471         { BT_AMPS_CDPD,            "AMPS CDPD" },
472         { BT_PDC_CSD,              "PDC CSD" },
473         { BT_PDC_PACKET_DATA,      "PDC Packet data" },
474         { BT_IDEN_SMS,             "IDEN SMS" },
475         { BT_IDEN_CSD,             "IDEN CSD" },
476         { BT_IDEN_PACKET_DATA,     "IDEN Packet data" },
477         { BT_PAGING_FLEX,          "Paging network FLEX(TM)" },
478         { BT_PHS_SMS,              "PHS SMS" },
479         { BT_PHS_CSD,              "PHS CSD" },
480         { BT_GSM_USSD_GSM_SC,      "GSM USSD (GSM Service Code addresses)" },
481         { BT_TETRA_SDS_ITSI,       "TETRA SDS (ITSI addresses)" },
482         { BT_TETRA_SDS_MSISDN,     "TETRA SDS (MSISDN addresses)" },
483         { BT_TETRA_PACKET_DATA,    "TETRA Packet data" },
484         { BT_PAGING_REFLEX,        "Paging network ReFLEX(TM)" },
485         { BT_GSM_USSD_MSISDN,      "GSM USSD (MSISDN addresses)" },
486         { BT_MOBITEX_MPAK,         "Mobitex MPAK" },
487         { BT_ANSI_136_GHOST,       "ANSI-136 GHOST/R-Data" },
488         { 0,                       NULL }
489 };
490
491 static const value_string vals_content_types[] = {
492         { 0x00, "*/*" },
493         { 0x01, "text/*" },
494         { 0x02, "text/html" },
495         { 0x03, "text/plain" },
496         { 0x04, "text/x-hdml" },
497         { 0x05, "text/x-ttml" },
498         { 0x06, "text/x-vCalendar" },
499         { 0x07, "text/x-vCard" },
500         { 0x08, "text/vnd.wap.wml" },
501         { 0x09, "text/vnd.wap.wmlscript" },
502         { 0x0A, "text/vnd.wap.channel" },
503         { 0x0B, "Multipart/*" },
504         { 0x0C, "Multipart/mixed" },
505         { 0x0D, "Multipart/form-data" },
506         { 0x0E, "Multipart/byteranges" },
507         { 0x0F, "Multipart/alternative" },
508         { 0x10, "application/*" },
509         { 0x11, "application/java-vm" },
510         { 0x12, "application/x-www-form-urlencoded" },
511         { 0x13, "application/x-hdmlc" },
512         { 0x14, "application/vnd.wap.wmlc" },
513         { 0x15, "application/vnd.wap.wmlscriptc" },
514         { 0x16, "application/vnd.wap.channelc" },
515         { 0x17, "application/vnd.wap.uaprof" },
516         { 0x18, "application/vnd.wap.wtls-ca-certificate" },
517         { 0x19, "application/vnd.wap.wtls-user-certificate" },
518         { 0x1A, "application/x-x509-ca-cert" },
519         { 0x1B, "application/x-x509-user-cert" },
520         { 0x1C, "image/*" },
521         { 0x1D, "image/gif" },
522         { 0x1E, "image/jpeg" },
523         { 0x1F, "image/tiff" },
524         { 0x20, "image/png" },
525         { 0x21, "image/vnd.wap.wbmp" },
526         { 0x22, "application/vnd.wap.multipart.*" },
527         { 0x23, "application/vnd.wap.multipart.mixed" },
528         { 0x24, "application/vnd.wap.multipart.form-data" },
529         { 0x25, "application/vnd.wap.multipart.byteranges" },
530         { 0x26, "application/vnd.wap.multipart.alternative" },
531         { 0x27, "application/xml" },
532         { 0x28, "text/xml" },
533         { 0x29, "application/vnd.wap.wbxml" },
534         { 0x2A, "application/x-x968-cross-cert" },
535         { 0x2B, "application/x-x968-ca-cert" },
536         { 0x2C, "application/x-x968-user-cert" },
537         { 0x2D, "text/vnd.wap.si" },
538         { 0x2E, "application/vnd.wap.sic" },
539         { 0x2F, "text/vnd.wap.sl" },
540         { 0x30, "application/vnd.wap.slc" },
541         { 0x31, "text/vnd.wap.co" },
542         { 0x32, "application/vnd.wap.coc" },
543         { 0x33, "application/vnd.wap.multipart.related" },
544         { 0x34, "application/vnd.wap.sia" },
545         { 0x35, "text/vnd.wap.connectivity-xml" },
546         { 0x36, "application/vnd.wap.connectivity-wbxml" },
547         { 0x37, "application/pkcs7-mime" },
548         { 0x38, "application/vnd.wap.hashed-certificate" },
549         { 0x39, "application/vnd.wap.signed-certificate" },
550         { 0x3A, "application/vnd.wap.cert-response" },
551         { 0x3B, "application/xhtml+xml" },
552         { 0x3C, "application/wml+xml" },
553         { 0x3D, "text/css" },
554         { 0x3E, "application/vnd.wap.mms-message" },
555         { 0x3F, "application/vnd.wap.rollover-certificate" },
556         { 0x00, NULL }
557 };
558
559 static const value_string vals_languages[] = {
560         { 0x01, "Afar (aa)" },
561         { 0x02, "Abkhazian (ab)" },
562         { 0x03, "Afrikaans (af)" },
563         { 0x04, "Amharic (am)" },
564         { 0x05, "Arabic (ar)" },
565         { 0x06, "Assamese (as)" },
566         { 0x07, "Aymara (ay)" },
567         { 0x08, "Azerbaijani (az)" },
568         { 0x09, "Bashkir (ba)" },
569         { 0x0A, "Byelorussian (be)" },
570         { 0x0B, "Bulgarian (bg)" },
571         { 0x0C, "Bihari (bh)" },
572         { 0x0D, "Bislama (bi)" },
573         { 0x0E, "Bengali; Bangla (bn)" },
574         { 0x0F, "Tibetan (bo)" },
575         { 0x10, "Breton (br)" },
576         { 0x11, "Catalan (ca)" },
577         { 0x12, "Corsican (co)" },
578         { 0x13, "Czech (cs)" },
579         { 0x14, "Welsh (cy)" },
580         { 0x15, "Danish (da)" },
581         { 0x16, "German (de)" },
582         { 0x17, "Bhutani (dz)" },
583         { 0x18, "Greek (el)" },
584         { 0x19, "English (en)" },
585         { 0x1A, "Esperanto (eo)" },
586         { 0x1B, "Spanish (es)" },
587         { 0x1C, "Estonian (et)" },
588         { 0x1D, "Basque (eu)" },
589         { 0x1E, "Persian (fa)" },
590         { 0x1F, "Finnish (fi)" },
591         { 0x20, "Fiji (fj)" },
592         { 0x22, "French (fr)" },
593         { 0x24, "Irish (ga)" },
594         { 0x25, "Scots Gaelic (gd)" },
595         { 0x26, "Galician (gl)" },
596         { 0x27, "Guarani (gn)" },
597         { 0x28, "Gujarati (gu)" },
598         { 0x29, "Hausa (ha)" },
599         { 0x2A, "Hebrew (formerly iw) (he)" },
600         { 0x2B, "Hindi (hi)" },
601         { 0x2C, "Croatian (hr)" },
602         { 0x2D, "Hungarian (hu)" },
603         { 0x2E, "Armenian (hy)" },
604         { 0x30, "Indonesian (formerly in) (id)" },
605         { 0x47, "Maori (mi)" },
606         { 0x48, "Macedonian (mk)" },
607         { 0x49, "Malayalam (ml)" },
608         { 0x4A, "Mongolian (mn)" },
609         { 0x4B, "Moldavian (mo)" },
610         { 0x4C, "Marathi (mr)" },
611         { 0x4D, "Malay (ms)" },
612         { 0x4E, "Maltese (mt)" },
613         { 0x4F, "Burmese (my)" },
614         { 0x51, "Nepali (ne)" },
615         { 0x52, "Dutch (nl)" },
616         { 0x53, "Norwegian (no)" },
617         { 0x54, "Occitan (oc)" },
618         { 0x55, "(Afan) Oromo (om)" },
619         { 0x56, "Oriya (or)" },
620         { 0x57, "Punjabi (pa)" },
621         { 0x58, "Polish (po)" },
622         { 0x59, "Pashto, Pushto (ps)" },
623         { 0x5A, "Portuguese (pt)" },
624         { 0x5B, "Quechua (qu)" },
625         { 0x5D, "Kirundi (rn)" },
626         { 0x5E, "Romanian (ro)" },
627         { 0x5F, "Russian (ru)" },
628         { 0x60, "Kinyarwanda (rw)" },
629         { 0x61, "Sanskrit (sa)" },
630         { 0x62, "Sindhi (sd)" },
631         { 0x63, "Sangho (sg)" },
632         { 0x64, "Serbo-Croatian (sh)" },
633         { 0x65, "Sinhalese (si)" },
634         { 0x66, "Slovak (sk)" },
635         { 0x67, "Slovenian (sl)" },
636         { 0x68, "Samoan (sm)" },
637         { 0x69, "Shona (sn)" },
638         { 0x6A, "Somali (so)" },
639         { 0x6B, "Albanian (sq)" },
640         { 0x6C, "Serbian (sr)" },
641         { 0x6D, "Siswati (ss)" },
642         { 0x6E, "Sesotho (st)" },
643         { 0x6F, "Sundanese (su)" },
644         { 0x70, "Swedish (sv)" },
645         { 0x71, "Swahili (sw)" },
646         { 0x72, "Tamil (ta)" },
647         { 0x73, "Telugu (te)" },
648         { 0x74, "Tajik (tg)" },
649         { 0x75, "Thai (th)" },
650         { 0x76, "Tigrinya (ti)" },
651         { 0x81, "Nauru (na)" },
652         { 0x82, "Faeroese (fo)" },
653         { 0x83, "Frisian (fy)" },
654         { 0x84, "Interlingua (ia)" },
655         { 0x8C, "Rhaeto-Romance (rm)" },
656         { 0x00, NULL }
657 };
658
659 static const value_string vals_accept_ranges[] = {
660         { 0x00, "None" },
661         { 0x01, "Bytes" },
662         { 0x00, NULL }
663 };
664
665 #define NO_CACHE                0x00
666 #define NO_STORE                0x01
667 #define MAX_AGE                 0x02
668 #define MAX_STALE               0x03
669 #define MIN_FRESH               0x04
670 #define ONLY_IF_CACHED          0x05
671 #define PUBLIC                  0x06
672 #define PRIVATE                 0x07
673 #define NO_TRANSFORM            0x08
674 #define MUST_REVALIDATE         0x09
675 #define PROXY_REVALIDATE        0x0A
676 #define S_MAXAGE                0x0B
677
678 static const value_string vals_cache_control[] = {
679         { NO_CACHE,         "No-cache" },
680         { NO_STORE,         "No-store" },
681         { MAX_AGE,          "Max-age" },
682         { MAX_STALE,        "Max-stale" },
683         { MIN_FRESH,        "Min-fresh" },
684         { ONLY_IF_CACHED,   "Only-if-cached" },
685         { PUBLIC,           "Public" },
686         { PRIVATE,          "Private" },
687         { NO_TRANSFORM,     "No-transform" },
688         { MUST_REVALIDATE,  "Must-revalidate" },
689         { PROXY_REVALIDATE, "Proxy-revalidate" },
690         { S_MAXAGE,         "S-max-age" },
691         { 0x00,             NULL }
692 };
693
694 static const value_string vals_connection[] = {
695         { 0x00, "Close" },
696         { 0x00, NULL }
697 };
698
699 static const value_string vals_transfer_encoding[] = {
700         { 0x00, "Chunked" },
701         { 0x00, NULL }
702 };
703
704 /*
705  * Redirect flags.
706  */
707 #define PERMANENT_REDIRECT      0x80
708 #define REUSE_SECURITY_SESSION  0x40
709
710 /*
711  * Redirect address flags and length.
712  */
713 #define BEARER_TYPE_INCLUDED    0x80
714 #define PORT_NUMBER_INCLUDED    0x40
715 #define ADDRESS_LEN             0x3f
716
717 static const true_false_string yes_no_truth = { 
718         "Yes" ,
719         "No"
720 };
721
722 /*
723  * Windows appears to define DELETE.
724  */
725 #ifdef DELETE
726 #undef DELETE
727 #endif
728
729 enum {
730         RESERVED                = 0x00,
731         CONNECT                 = 0x01,
732         CONNECTREPLY            = 0x02,
733         REDIRECT                = 0x03,                 /* No sample data */
734         REPLY                   = 0x04,
735         DISCONNECT              = 0x05,
736         PUSH                    = 0x06,                 /* No sample data */
737         CONFIRMEDPUSH           = 0x07,                 /* No sample data */
738         SUSPEND                 = 0x08,                 /* No sample data */
739         RESUME                  = 0x09,                 /* No sample data */
740
741         GET                     = 0x40,
742         OPTIONS                 = 0x41,                 /* No sample data */
743         HEAD                    = 0x42,                 /* No sample data */
744         DELETE                  = 0x43,                 /* No sample data */
745         TRACE                   = 0x44,                 /* No sample data */
746
747         POST                    = 0x60,
748         PUT                     = 0x61,                 /* No sample data */
749 };
750
751 typedef enum {
752         VALUE_LEN_SUPPLIED,
753         VALUE_IS_TEXT_STRING,
754         VALUE_IN_LEN,
755 } value_type_t;
756
757 static dissector_table_t wsp_dissector_table;
758 static heur_dissector_list_t heur_subdissector_list;
759
760 static void add_uri (proto_tree *, frame_data *, tvbuff_t *, guint, guint);
761 static void add_headers (proto_tree *, tvbuff_t *);
762 static int add_well_known_header (proto_tree *, tvbuff_t *, int, guint8);
763 static int add_unknown_header (proto_tree *, tvbuff_t *, int, guint8);
764 static int add_application_header (proto_tree *, tvbuff_t *, int);
765 static void add_accept_header (proto_tree *, tvbuff_t *, int,
766     tvbuff_t *, value_type_t, int);
767 static void add_accept_xxx_header (proto_tree *, tvbuff_t *, int,
768     tvbuff_t *, value_type_t, int, int, int, const value_string *,
769     const char *);
770 static void add_accept_ranges_header (proto_tree *, tvbuff_t *, int,
771     tvbuff_t *, value_type_t, int);
772 static void add_cache_control_header (proto_tree *, tvbuff_t *, int,
773     tvbuff_t *, value_type_t, int);
774 static int add_cache_control_field_name (proto_tree *, tvbuff_t *, int, guint);
775 static void add_connection_header (proto_tree *, tvbuff_t *, int,
776     tvbuff_t *, value_type_t, int);
777 static void add_content_type_value (proto_tree *, tvbuff_t *, int, int,
778     tvbuff_t *, value_type_t, int, int, int, guint *, const char **);
779 static void add_wap_application_id_header (proto_tree *, tvbuff_t *, int,
780     tvbuff_t *, value_type_t, int);
781 static void add_integer_value_header (proto_tree *, tvbuff_t *, int,
782     tvbuff_t *, value_type_t, int, int, guint8);
783 static void add_string_value_header (proto_tree *, tvbuff_t *, int,
784     tvbuff_t *, value_type_t, int, int, guint8);
785 static void add_quoted_string_value_header (proto_tree *, tvbuff_t *, int,
786     tvbuff_t *, value_type_t, int, int, guint8);
787 static void add_date_value_header (proto_tree *, tvbuff_t *, int,
788     tvbuff_t *, value_type_t, int, int, guint8);
789 static int add_parameter (proto_tree *, tvbuff_t *, int);
790 static int add_untyped_parameter (proto_tree *, tvbuff_t *, int, int);
791 static int add_parameter_charset (proto_tree *, tvbuff_t *, int, int);
792 static int add_constrained_encoding (proto_tree *, tvbuff_t *, int, int);
793 static int add_parameter_type (proto_tree *, tvbuff_t *, int, int);
794 static int add_parameter_text (proto_tree *, tvbuff_t *, int, int, int, const char *);
795 static void add_post_data (proto_tree *, tvbuff_t *, guint, const char *);
796 static void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
797 static void add_pragma_header (proto_tree *, tvbuff_t *, int, tvbuff_t *,
798     value_type_t, int);
799 static void add_transfer_encoding_header (proto_tree *, tvbuff_t *, int,
800     tvbuff_t *, value_type_t, int);
801 static void add_warning_header (proto_tree *, tvbuff_t *, int, tvbuff_t *,
802     value_type_t, int);
803 static void add_accept_application_header (proto_tree *, tvbuff_t *, int,
804     tvbuff_t *, value_type_t, int);
805 static void add_capabilities (proto_tree *tree, tvbuff_t *tvb, int type);
806 static void add_capability_vals(tvbuff_t *, gboolean, int, guint, guint, char *, size_t);
807 static value_type_t get_value_type_len (tvbuff_t *, int, guint *, int *, int *);
808 static guint get_uintvar (tvbuff_t *, guint, guint);
809 static gint get_integer (tvbuff_t *, guint, guint, value_type_t, guint *);
810
811 /* Code to actually dissect the packets */
812 static void
813 dissect_redirect(tvbuff_t *tvb, int offset, packet_info *pinfo,
814     proto_tree *tree, dissector_handle_t dissector_handle)
815 {
816         guint8 flags;
817         proto_item *ti;
818         proto_tree *flags_tree;
819         guint8 bearer_type;
820         guint8 address_flags_len;
821         int address_len;
822         proto_tree *atf_tree;
823         guint16 port_num;
824         guint32 address_ipv4;
825         struct e_in6_addr address_ipv6;
826         address redir_address;
827         conversation_t *conv;
828
829         flags = tvb_get_guint8 (tvb, offset);
830         if (tree) {
831                 ti = proto_tree_add_uint (tree, hf_wsp_redirect_flags,
832                     tvb, offset, 1, flags);
833                 flags_tree = proto_item_add_subtree (ti, ett_redirect_flags);
834                 proto_tree_add_boolean (flags_tree, hf_wsp_redirect_permanent,
835                     tvb, offset, 1, flags);
836                 proto_tree_add_boolean (flags_tree, hf_wsp_redirect_reuse_security_session,
837                     tvb, offset, 1, flags);
838         }
839         offset++;
840         while (tvb_reported_length_remaining (tvb, offset) > 0) {
841                 address_flags_len = tvb_get_guint8 (tvb, offset);
842                 if (tree) {
843                         ti = proto_tree_add_uint (tree, hf_wsp_redirect_afl,
844                             tvb, offset, 1, address_flags_len);
845                         atf_tree = proto_item_add_subtree (ti, ett_redirect_afl);
846                         proto_tree_add_boolean (atf_tree, hf_wsp_redirect_afl_bearer_type_included,
847                             tvb, offset, 1, address_flags_len);
848                         proto_tree_add_boolean (atf_tree, hf_wsp_redirect_afl_port_number_included,
849                             tvb, offset, 1, address_flags_len);
850                         proto_tree_add_uint (atf_tree, hf_wsp_redirect_afl_address_len,
851                             tvb, offset, 1, address_flags_len);
852                 }
853                 offset++;
854                 if (address_flags_len & BEARER_TYPE_INCLUDED) {
855                         bearer_type = tvb_get_guint8 (tvb, offset);
856                         if (tree) {
857                                 proto_tree_add_uint (tree, hf_wsp_redirect_bearer_type,
858                                     tvb, offset, 1, bearer_type);
859                         }
860                         offset++;
861                 } else
862                         bearer_type = 0x00;     /* XXX */
863                 if (address_flags_len & PORT_NUMBER_INCLUDED) {
864                         port_num = tvb_get_ntohs (tvb, offset);
865                         if (tree) {
866                                 proto_tree_add_uint (tree, hf_wsp_redirect_port_num,
867                                     tvb, offset, 2, port_num);
868                         }
869                         offset += 2;
870                 } else {
871                         /*
872                          * Redirecting to the same server port number as was
873                          * being used, i.e. the source port number of this
874                          * redirect.
875                          */
876                         port_num = pinfo->srcport;
877                 }
878                 address_len = address_flags_len & ADDRESS_LEN;
879                 if (!(address_flags_len & BEARER_TYPE_INCLUDED)) {
880                         /*
881                          * We don't have the bearer type in the message,
882                          * so we don't know the address type.
883                          * (It's the same bearer type as the original
884                          * connection.)
885                          */
886                         goto unknown_address_type;
887                 }
888
889                 /*
890                  * We know the bearer type, so we know the address type.
891                  */
892                 switch (bearer_type) {
893
894                 case BT_IPv4:
895                 case BT_IS_95_CSD:
896                 case BT_IS_95_PACKET_DATA:
897                 case BT_ANSI_136_CSD:
898                 case BT_ANSI_136_PACKET_DATA:
899                 case BT_GSM_CSD:
900                 case BT_GSM_GPRS:
901                 case BT_GSM_USSD_IPv4:
902                 case BT_AMPS_CDPD:
903                 case BT_PDC_CSD:
904                 case BT_PDC_PACKET_DATA:
905                 case BT_IDEN_CSD:
906                 case BT_IDEN_PACKET_DATA:
907                 case BT_PHS_CSD:
908                 case BT_TETRA_PACKET_DATA:
909                         /*
910                          * IPv4.
911                          */
912                         if (address_len != 4) {
913                                 /*
914                                  * Say what?
915                                  */
916                                 goto unknown_address_type;
917                         }
918                         tvb_memcpy(tvb, (guint8 *)&address_ipv4, offset, 4);
919                         if (tree) {
920                                 proto_tree_add_ipv4 (tree,
921                                     hf_wsp_redirect_ipv4_addr,
922                                     tvb, offset, 4, address_ipv4);
923                         }
924
925                         /*
926                          * Create a conversation so that the
927                          * redirected session will be dissected
928                          * as WAP.
929                          */
930                         redir_address.type = AT_IPv4;
931                         redir_address.len = 4;
932                         redir_address.data = (const guint8 *)&address_ipv4;
933                         conv = find_conversation(&redir_address, &pinfo->dst,
934                             PT_UDP, port_num, 0, NO_PORT_B);
935                         if (conv == NULL) {
936                                 conv = conversation_new(&redir_address,
937                                     &pinfo->dst, PT_UDP, port_num, 0, NO_PORT2);
938                         }
939                         conversation_set_dissector(conv, dissector_handle);
940                         break;
941
942                 case BT_IPv6:
943                         /*
944                          * IPv6.
945                          */
946                         if (address_len != 16) {
947                                 /*
948                                  * Say what?
949                                  */
950                                 goto unknown_address_type;
951                         }
952                         tvb_memcpy(tvb, (guint8 *)&address_ipv6, offset, 16);
953                         if (tree) {
954                                 proto_tree_add_ipv6 (tree,
955                                     hf_wsp_redirect_ipv6_addr,
956                                     tvb, offset, 16, (guint8 *)&address_ipv6);
957                         }
958
959                         /*
960                          * Create a conversation so that the
961                          * redirected session will be dissected
962                          * as WAP.
963                          */
964                         redir_address.type = AT_IPv6;
965                         redir_address.len = 16;
966                         redir_address.data = (const guint8 *)&address_ipv4;
967                         conv = find_conversation(&redir_address, &pinfo->dst,
968                             PT_UDP, port_num, 0, NO_PORT_B);
969                         if (conv == NULL) {
970                                 conv = conversation_new(&redir_address,
971                                     &pinfo->dst, PT_UDP, port_num, 0, NO_PORT2);
972                         }
973                         conversation_set_dissector(conv, dissector_handle);
974                         break;
975
976                 unknown_address_type:
977                 default:
978                         if (address_len != 0) {
979                                 if (tree) {
980                                         proto_tree_add_item (tree,
981                                             hf_wsp_redirect_addr,
982                                             tvb, offset, address_len,
983                                             bo_little_endian);
984                                 }
985                         }
986                         break;
987                 }
988                 offset += address_len;
989         }
990 }
991
992 static void
993 dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
994     dissector_handle_t dissector_handle, gboolean is_connectionless)
995 {
996         frame_data *fdata = pinfo->fd;
997         int offset = 0;
998
999         guint8 pdut;
1000         guint count = 0;
1001         guint value = 0;
1002         guint uriLength = 0;
1003         guint uriStart = 0;
1004         guint capabilityLength = 0;
1005         guint capabilityStart = 0;
1006         guint headersLength = 0;
1007         guint headerLength = 0;
1008         guint headerStart = 0;
1009         guint nextOffset = 0;
1010         guint contentTypeStart = 0;
1011         guint contentType = 0;
1012         const char *contentTypeStr;
1013         tvbuff_t *tmp_tvb;
1014
1015 /* Set up structures we will need to add the protocol subtree and manage it */
1016         proto_item *ti;
1017         proto_tree *wsp_tree = NULL;
1018 /*      proto_tree *wsp_header_fixed; */
1019         
1020 /* This field shows up as the "Info" column in the display; you should make
1021    it, if possible, summarize what's in the packet, so that a user looking
1022    at the list of packets can tell what type of packet it is. */
1023     
1024         /* Connection-less mode has a TID first */
1025         if (is_connectionless)
1026         {
1027                 offset++;
1028         };
1029
1030         /* Find the PDU type */
1031         pdut = tvb_get_guint8 (tvb, offset);
1032
1033         /* Develop the string to put in the Info column */
1034         if (check_col(fdata, COL_INFO))
1035         {
1036                 col_append_fstr(fdata, COL_INFO, "WSP %s",
1037                         val_to_str (pdut, vals_pdu_type, "Unknown PDU type (0x%02x)"));
1038         };
1039
1040 /* In the interest of speed, if "tree" is NULL, don't do any work not
1041    necessary to generate protocol tree items. */
1042         if (tree) {
1043                 ti = proto_tree_add_item(tree, proto_wsp, tvb, 0,
1044                     tvb_length(tvb), bo_little_endian);
1045                 wsp_tree = proto_item_add_subtree(ti, ett_wsp);
1046
1047 /* Code to process the packet goes here */
1048 /*
1049                 wsp_header_fixed = proto_item_add_subtree(ti, ett_header );
1050 */
1051
1052                 /* Add common items: only TID and PDU Type */
1053
1054                 /* If this is connectionless, then the TID Field is always first */
1055                 if (is_connectionless)
1056                 {
1057                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_tid,tvb,
1058                                 0,1,bo_little_endian);
1059                 }
1060
1061                 ti = proto_tree_add_item(
1062                                 wsp_tree,               /* tree */
1063                                 hf_wsp_header_pdu_type, /* id */
1064                                 tvb, 
1065                                 offset,                 /* start of high light */
1066                                 1,                      /* length of high light */
1067                                 bo_little_endian        /* value */
1068                      );
1069         }
1070         offset++;
1071
1072         switch (pdut)
1073         {
1074                 case CONNECT:
1075                 case CONNECTREPLY:
1076                 case RESUME:
1077                         if (tree) {
1078                                 if (pdut == CONNECT)
1079                                 {
1080                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
1081                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
1082                                         offset++;
1083                                 } else {
1084                                         count = 0;      /* Initialise count */
1085                                         value = tvb_get_guintvar (tvb, offset, &count);
1086                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
1087                                         offset += count;
1088                                 }
1089                                 capabilityStart = offset;
1090                                 count = 0;      /* Initialise count */
1091                                 capabilityLength = tvb_get_guintvar (tvb, offset, &count);
1092                                 offset += count;
1093                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
1094
1095                                 if (pdut != RESUME)
1096                                 {
1097                                         count = 0;      /* Initialise count */
1098                                         headerLength = tvb_get_guintvar (tvb, offset, &count);
1099                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset,count,headerLength);
1100                                         offset += count;
1101                                         capabilityStart = offset;
1102                                         headerStart = capabilityStart + capabilityLength;
1103                                 } else {
1104                                                 /* Resume computes the headerlength by remaining bytes */
1105                                         capabilityStart = offset;
1106                                         headerStart = capabilityStart + capabilityLength;
1107                                         headerLength = tvb_reported_length_remaining (tvb, headerStart);
1108                                 }
1109                                 if (capabilityLength > 0)
1110                                 {
1111                                         tmp_tvb = tvb_new_subset (tvb, offset, capabilityLength, capabilityLength);
1112                                         add_capabilities (wsp_tree, tmp_tvb, pdut);
1113                                         offset += capabilityLength;
1114                                 }
1115
1116                                 if (headerLength > 0)
1117                                 {
1118                                         tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
1119                                         add_headers (wsp_tree, tmp_tvb);
1120                                 }
1121                         }
1122
1123                         break;
1124
1125                 case REDIRECT:
1126                         dissect_redirect(tvb, offset, pinfo, wsp_tree,
1127                           dissector_handle);
1128                         break;
1129
1130                 case DISCONNECT:
1131                 case SUSPEND:
1132                         if (tree) {
1133                                 count = 0;      /* Initialise count */
1134                                 value = tvb_get_guintvar (tvb, offset, &count);
1135                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
1136                         }
1137                         break;
1138
1139                 case GET:
1140                         count = 0;      /* Initialise count */
1141                                 /* Length of URI and size of URILen field */
1142                         value = tvb_get_guintvar (tvb, offset, &count);
1143                         nextOffset = offset + count;
1144                         add_uri (wsp_tree, fdata, tvb, offset, nextOffset);
1145                         if (tree) {
1146                                 offset += (value+count); /* VERIFY */
1147                                 tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
1148                                 add_headers (wsp_tree, tmp_tvb);
1149                         }
1150                         break;
1151
1152                 case POST:
1153                         uriStart = offset;
1154                         count = 0;      /* Initialise count */
1155                         uriLength = tvb_get_guintvar (tvb, offset, &count);
1156                         headerStart = uriStart+count;
1157                         count = 0;      /* Initialise count */
1158                         headersLength = tvb_get_guintvar (tvb, headerStart, &count);
1159                         offset = headerStart + count;
1160
1161                         add_uri (wsp_tree, fdata, tvb, uriStart, offset);
1162                         if (tree) {
1163                                 offset += uriLength;
1164
1165                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headersLength);
1166
1167                                 if (headersLength == 0)
1168                                         break;
1169
1170                                 contentTypeStart = offset;
1171                                 nextOffset = add_content_type (wsp_tree,
1172                                     tvb, offset, &contentType,
1173                                     &contentTypeStr);
1174
1175                                 /* Add headers subtree that will hold the headers fields */
1176                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1177                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1178                                 if (headerLength > 0)
1179                                 {
1180                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1181                                         add_headers (wsp_tree, tmp_tvb);
1182                                 }
1183
1184                                 /* TODO: Post DATA */
1185                                 /* Runs from start of headers+headerLength to end of frame */
1186                                 offset = nextOffset+headerLength;
1187                                 tmp_tvb = tvb_new_subset (tvb, offset, tvb_reported_length (tvb)-offset, tvb_reported_length (tvb)-offset);
1188                                 add_post_data (wsp_tree, tmp_tvb,
1189                                     contentType, contentTypeStr);
1190                         }
1191                         if (tvb_reported_length_remaining(tvb, headerStart + count + uriLength + headersLength) > 0)
1192                         {
1193                                 tmp_tvb = tvb_new_subset (tvb, headerStart + count + uriLength + headersLength, -1, -1);
1194                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1195                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1196                         }
1197                         break;
1198
1199                 case REPLY:
1200                         count = 0;      /* Initialise count */
1201                         headersLength = tvb_get_guintvar (tvb, offset+1, &count);
1202                         headerStart = offset + count + 1;
1203                         if (tree) {
1204                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
1205                                 nextOffset = offset + 1 + count;
1206                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,headersLength);
1207
1208                                 if (headersLength == 0)
1209                                         break;
1210
1211                                 contentTypeStart = nextOffset;
1212                                 nextOffset = add_content_type (wsp_tree,
1213                                     tvb, nextOffset, &contentType,
1214                                     &contentTypeStr);
1215
1216                                 /* Add headers subtree that will hold the headers fields */
1217                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1218                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1219                                 if (headerLength > 0)
1220                                 {
1221                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1222                                         add_headers (wsp_tree, tmp_tvb);
1223                                 }
1224                                 offset += count+headersLength+1;
1225
1226                                 /* TODO: Data - decode WMLC */
1227                                 /* Runs from offset+1+count+headerLength+1 to end of frame */
1228                                 if (tvb_reported_length_remaining (tvb, offset) > 0)
1229                                 {
1230                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,tvb_length_remaining(tvb, offset),bo_little_endian);
1231                                 }
1232                         }
1233                         if (tvb_reported_length_remaining(tvb, headerStart + headersLength) > 0)
1234                         {
1235                                 tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength, -1, -1);
1236                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1237                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1238                         }
1239                         break;
1240
1241                 case PUSH:
1242                 case CONFIRMEDPUSH:
1243                         count = 0;      /* Initialise count */
1244                         headersLength = tvb_get_guintvar (tvb, offset, &count);
1245                         headerStart = offset + count;
1246
1247                         if (tree) {
1248                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset,count,headersLength);
1249
1250                                 if (headersLength == 0)
1251                                         break;
1252
1253                                 offset += count;
1254                                 contentTypeStart = offset;
1255                                 nextOffset = add_content_type (wsp_tree,
1256                                     tvb, offset, &contentType,
1257                                     &contentTypeStr);
1258
1259                                 /* Add headers subtree that will hold the headers fields */
1260                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1261                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1262                                 if (headerLength > 0)
1263                                 {
1264                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1265                                         add_headers (wsp_tree, tmp_tvb);
1266                                 }
1267                                 offset += headersLength;
1268
1269                                 /* Push DATA */
1270                                 if (tvb_reported_length_remaining (tvb, offset) > 0)
1271                                 {
1272                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_push_data,tvb,offset,tvb_length_remaining(tvb, offset),bo_little_endian);
1273                                 }
1274                         }
1275                         if (tvb_reported_length_remaining(tvb, headerStart + headersLength) > 0)
1276                         {
1277                                 tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength, -1, -1);
1278                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1279                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1280                         }
1281                         break;
1282
1283         }
1284 }
1285
1286 /*
1287  * Called directly from UDP.
1288  * Put "WSP" into the "Protocol" column.
1289  */
1290 static void
1291 dissect_wsp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1292 {
1293         if (check_col(pinfo->fd, COL_PROTOCOL))
1294                 col_set_str(pinfo->fd, COL_PROTOCOL, "WSP" );
1295         if (check_col(pinfo->fd, COL_INFO))
1296                 col_clear(pinfo->fd, COL_INFO);
1297
1298         dissect_wsp_common(tvb, pinfo, tree, wsp_fromudp_handle, TRUE);
1299 }
1300
1301 /*
1302  * Called from a higher-level WAP dissector, in connection-oriented mode.
1303  * Leave the "Protocol" column alone - the dissector calling us should
1304  * have set it.
1305  */
1306 static void
1307 dissect_wsp_fromwap_co(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1308 {
1309         /*
1310          * XXX - what about WTLS->WTP->WSP?
1311          */
1312         dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, FALSE);
1313 }
1314
1315 /*
1316  * Called from a higher-level WAP dissector, in connectionless mode.
1317  * Leave the "Protocol" column alone - the dissector calling us should
1318  * have set it.
1319  */
1320 static void
1321 dissect_wsp_fromwap_cl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1322 {
1323         /*
1324          * XXX - what about WTLS->WSP?
1325          */
1326         if (check_col(pinfo->fd, COL_INFO))
1327         {
1328                 col_clear(pinfo->fd, COL_INFO);
1329         }
1330         dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, TRUE);
1331 }
1332
1333 static void
1334 add_uri (proto_tree *tree, frame_data *fdata, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
1335 {
1336         proto_item *ti;
1337         char *newBuffer;
1338
1339         guint count = 0;
1340         guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
1341
1342         if (tree)
1343                 ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
1344
1345         newBuffer = g_malloc (uriLen+2);
1346         newBuffer[0] = ' ';  /* This is for COL_INFO */
1347         strncpy (newBuffer+1, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
1348         newBuffer[uriLen+1] = 0;
1349         if (tree)
1350                 ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer+1);
1351         if (check_col(fdata, COL_INFO)) {
1352                 col_append_str(fdata, COL_INFO, newBuffer);
1353         };
1354         g_free (newBuffer);
1355 }
1356
1357 static void
1358 add_headers (proto_tree *tree, tvbuff_t *tvb)
1359 {
1360         proto_item *ti;
1361         proto_tree *wsp_headers;
1362         guint offset = 0;
1363         guint headersLen = tvb_reported_length (tvb);
1364         guint headerStart = 0;
1365         guint peek = 0;
1366         guint pageCode = 1;
1367
1368 #ifdef DEBUG
1369         fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, headersLen);
1370 #endif
1371
1372         /* End of buffer */
1373         if (headersLen <= 0)
1374         {
1375                 return;
1376         }
1377
1378 #ifdef DEBUG
1379         fprintf (stderr, "dissect_wsp: Headers to process\n");
1380 #endif
1381
1382         ti = proto_tree_add_item (tree, hf_wsp_headers_section,tvb,offset,headersLen,bo_little_endian);
1383         wsp_headers = proto_item_add_subtree( ti, ett_headers );
1384
1385         /* Parse Headers */
1386
1387         while (offset < headersLen)
1388         {
1389                 /* Loop round each header */
1390                 headerStart = offset;
1391                 peek = tvb_get_guint8 (tvb, headerStart);
1392
1393                 if (peek < 32)          /* Short-cut shift delimiter */
1394                 {
1395                         pageCode = peek;
1396                         proto_tree_add_uint (wsp_headers,
1397                             hf_wsp_header_shift_code, tvb, offset, 1,
1398                             pageCode);
1399                         offset += 1;
1400                         continue;
1401                 }
1402                 else if (peek == 0x7F)  /* Shift delimiter */
1403                 {
1404                         pageCode = tvb_get_guint8(tvb, offset+1);
1405                         proto_tree_add_uint (wsp_headers,
1406                             hf_wsp_header_shift_code, tvb, offset, 2,
1407                             pageCode);
1408                         offset += 2;
1409                         continue;
1410                 }
1411                 else if (peek < 127)
1412                 {
1413 #ifdef DEBUG
1414                         fprintf (stderr, "dissect_wsp: header: application-header start %d (0x%02X)\n", peek, peek);
1415 #endif
1416                         /*
1417                          * Token-text, followed by Application-specific-value.
1418                          */
1419                         offset = add_application_header (wsp_headers, tvb,
1420                             headerStart);
1421                 }
1422                 else if (peek & 0x80)
1423                 {
1424 #ifdef DEBUG
1425                         fprintf (stderr, "dissect_wsp: header: well-known %d (0x%02X)\n", peek, peek);
1426 #endif
1427                         /*
1428                          * Well-known-header; the lower 7 bits of "peek"
1429                          * are the header code.
1430                          */
1431                         if (pageCode == 1)
1432                         {
1433                                 offset = add_well_known_header (wsp_headers,
1434                                     tvb, headerStart, peek & 0x7F);
1435                         }
1436                         else 
1437                         {
1438                                 offset = add_unknown_header (wsp_headers,
1439                                     tvb, headerStart, peek & 0x7F);
1440                         }
1441                 }
1442         }
1443 }
1444
1445 static int
1446 add_well_known_header (proto_tree *tree, tvbuff_t *tvb, int offset,
1447     guint8 headerType)
1448 {
1449         int headerStart;
1450         value_type_t valueType;
1451         int headerLen;
1452         guint valueLen;
1453         int valueStart;
1454         tvbuff_t *header_buff;
1455         tvbuff_t *value_buff;
1456
1457 #ifdef DEBUG
1458         fprintf (stderr, "dissect_wsp: Got header 0x%02x\n", headerType);
1459 #endif
1460         headerStart = offset;
1461
1462         /*
1463          * Skip the Short-Integer header type.
1464          */
1465         offset++;
1466
1467         /*
1468          * Get the value type and length (or, if the type is VALUE_IN_LEN,
1469          * meaning the value is a Short-integer, get the value type
1470          * and the value itself).
1471          */ 
1472         valueType = get_value_type_len (tvb, offset, &valueLen,
1473             &valueStart, &offset);
1474         headerLen = offset - headerStart;
1475
1476         /*
1477          * Get a tvbuff for the entire header.
1478          * XXX - cut the actual length short so that it doesn't run
1479          * past the actual length of tvb.
1480          */
1481         header_buff = tvb_new_subset (tvb, headerStart, headerLen,
1482             headerLen);
1483
1484         /*
1485          * If the value wasn't in the length, get a tvbuff for the value.
1486          * XXX - can valueLen be 0?
1487          * XXX - cut the actual length short so that it doesn't run
1488          * past the actual length of tvb.
1489          */
1490         if (valueType != VALUE_IN_LEN) {
1491                 value_buff = tvb_new_subset (tvb, valueStart, valueLen,
1492                     valueLen);
1493         } else {
1494                 /*
1495                  * XXX - when the last dissector is tvbuffified,
1496                  * so that NULL is no longer a valid tvb pointer
1497                  * value in "proto_tree_add" calls, just
1498                  * set "value_buff" to NULL.
1499                  *
1500                  * XXX - can we already do that?  I.e., will that
1501                  * cause us always to crash if we mistakenly try
1502                  * to fetch the value of a VALUE_IN_LEN item?
1503                  */
1504                 value_buff = tvb_new_subset (tvb, headerStart, 0, 0);
1505         }
1506
1507         switch (headerType) {
1508
1509         case FN_ACCEPT:                 /* Accept */
1510                 add_accept_header (tree, header_buff, headerLen,
1511                     value_buff, valueType, valueLen);
1512                 break;
1513
1514         case FN_ACCEPT_CHARSET_DEP:     /* Accept-Charset */
1515                 /*
1516                  * XXX - should both encoding versions 1.1 and
1517                  * 1.3 be handled this way?
1518                  */
1519                 add_accept_xxx_header (tree, header_buff, headerLen,
1520                     value_buff, valueType, valueLen,
1521                     hf_wsp_header_accept_charset,
1522                     hf_wsp_header_accept_charset_str,
1523                     vals_character_sets, "Unknown charset (%u)");
1524                 break;
1525
1526         case FN_ACCEPT_LANGUAGE:        /* Accept-Language */
1527                 add_accept_xxx_header (tree, header_buff, headerLen,
1528                     value_buff, valueType, valueLen,
1529                     hf_wsp_header_accept_language,
1530                     hf_wsp_header_accept_language_str,
1531                     vals_languages, "Unknown language (%u)");
1532                 break;
1533
1534         case FN_ACCEPT_RANGES:          /* Accept-Ranges */
1535                 add_accept_ranges_header (tree, header_buff, headerLen,
1536                     value_buff, valueType, valueLen);
1537                 break;
1538
1539         case FN_AGE:                    /* Age */
1540                 add_integer_value_header (tree, header_buff, headerLen,
1541                     value_buff, valueType, valueLen, hf_wsp_header_age,
1542                     headerType);
1543                 break;
1544
1545         case FN_CACHE_CONTROL_DEP:      /* Cache-Control */
1546         case FN_CACHE_CONTROL:
1547         case FN_CACHE_CONTROL14:
1548                 /*
1549                  * XXX - is the only difference in the three different
1550                  * versions (1.1, 1.3, 1.4) really only S_MAXAGE?
1551                  */
1552                 add_cache_control_header (tree, header_buff, headerLen,
1553                     value_buff, valueType, valueLen);
1554                 break;
1555                                 
1556         case FN_CONNECTION:     /* Connection */
1557                 add_connection_header (tree, header_buff, headerLen,
1558                     value_buff, valueType, valueLen);
1559                 break;
1560
1561         case FN_CONTENT_LENGTH:         /* Content-Length */
1562                 add_integer_value_header (tree, header_buff, headerLen,
1563                     value_buff, valueType, valueLen,
1564                     hf_wsp_header_content_length,
1565                     headerType);
1566                 break;
1567                                 
1568         case FN_DATE:                   /* Date */
1569                 add_date_value_header (tree, header_buff, headerLen,
1570                     value_buff, valueType, valueLen,
1571                     hf_wsp_header_date, headerType);
1572                 break;
1573
1574         case FN_ETAG:                   /* Etag */
1575                 add_string_value_header (tree, header_buff, headerLen,
1576                     value_buff, valueType, valueLen,
1577                     hf_wsp_header_etag, headerType);
1578                 break;
1579
1580         case FN_EXPIRES:                /* Expires */
1581                 add_date_value_header (tree, header_buff, headerLen,
1582                     value_buff, valueType, valueLen,
1583                     hf_wsp_header_expires, headerType);
1584                 break;
1585
1586         case FN_IF_MODIFIED_SINCE:      /* If-Modified-Since */
1587                 add_date_value_header (tree, header_buff, headerLen,
1588                     value_buff, valueType, valueLen,
1589                     hf_wsp_header_if_modified_since, headerType);
1590                 break;
1591                                 
1592         case FN_LOCATION:               /* Location */
1593                 add_string_value_header (tree, header_buff, headerLen,
1594                     value_buff, valueType, valueLen,
1595                     hf_wsp_header_location, headerType);
1596                 break;
1597
1598         case FN_LAST_MODIFIED:          /* Last-Modified */
1599                 add_date_value_header (tree, header_buff, headerLen,
1600                     value_buff, valueType, valueLen,
1601                     hf_wsp_header_last_modified, headerType);
1602                 break;
1603                                 
1604         case FN_PRAGMA:                 /* Pragma */
1605                 add_pragma_header (tree, header_buff, headerLen,
1606                     value_buff, valueType, valueLen);
1607                 break;
1608                                 
1609         case FN_SERVER:                 /* Server */
1610                 add_string_value_header (tree, header_buff, headerLen,
1611                     value_buff, valueType, valueLen,
1612                     hf_wsp_header_server, headerType);
1613                 break;
1614
1615         case FN_TRANSFER_ENCODING:      /* Transfer-Encoding */
1616                 add_transfer_encoding_header (tree, header_buff, headerLen,
1617                     value_buff, valueType, valueLen);
1618                 break;
1619
1620         case FN_USER_AGENT:             /* User-Agent */
1621                 add_string_value_header (tree, header_buff, headerLen,
1622                     value_buff, valueType, valueLen,
1623                     hf_wsp_header_user_agent, headerType);
1624                 break;
1625
1626         case FN_VIA:                    /* Via */
1627                 add_string_value_header (tree, header_buff, headerLen,
1628                     value_buff, valueType, valueLen,
1629                     hf_wsp_header_via, headerType);
1630                 break;
1631
1632         case FN_WARNING:                /* Warning */
1633                 add_warning_header (tree, header_buff, headerLen,
1634                     value_buff, valueType, valueLen);
1635                 break;
1636
1637         case FN_ACCEPT_APPLICATION:     /* Accept-Application */
1638                 add_accept_application_header (tree, header_buff, headerLen,
1639                     value_buff, valueType, valueLen);
1640                 break;
1641
1642         case FN_BEARER_INDICATION:      /* Bearer-Indication */
1643                 add_integer_value_header (tree, header_buff, headerLen,
1644                     value_buff, valueType, valueLen,
1645                     hf_wsp_header_bearer_indication, headerType);
1646                 break;
1647
1648         case FN_PROFILE:                /* Profile */
1649                 add_string_value_header (tree, header_buff, headerLen,
1650                     value_buff, valueType, valueLen,
1651                     hf_wsp_header_profile, headerType);
1652                 break;
1653
1654         case FN_X_WAP_APPLICATION_ID:   /* X-Wap-Application-Id */
1655                 add_wap_application_id_header (tree, header_buff, headerLen,
1656                     value_buff, valueType, valueLen);
1657                 break;
1658
1659         case FN_CONTENT_ID:             /* Content-ID   */
1660                 add_quoted_string_value_header (tree, header_buff, headerLen,
1661                     value_buff, valueType, valueLen,
1662                     hf_wsp_header_content_ID, headerType);
1663                 break;
1664
1665         default:
1666                 proto_tree_add_text (tree, header_buff, 0, headerLen,
1667                     "Unsupported Header: %s",
1668                     val_to_str (headerType, vals_field_names, "Unknown (0x%02X)"));
1669                 break;
1670         }
1671         return offset;
1672 }
1673
1674 static int
1675 add_unknown_header (proto_tree *tree, tvbuff_t *tvb, int offset,
1676     guint8 headerType)
1677 {
1678         int headerStart;
1679         int valueStart;
1680         value_type_t valueType;
1681         int headerLen;
1682         guint valueLen;
1683         int valueOffset;
1684
1685         headerStart = offset;
1686
1687         /*
1688          * Skip the Short-Integer header type.
1689          */
1690         offset++;
1691
1692         valueStart = offset;
1693
1694         /*
1695          * Get the value type and length (or, if the type is VALUE_IN_LEN,
1696          * meaning the value is a Short-integer, get the value type
1697          * and the value itself).
1698          */ 
1699         valueType = get_value_type_len (tvb, valueStart, &valueLen,
1700             &valueOffset, &offset);
1701         headerLen = offset - headerStart;
1702
1703         proto_tree_add_text (tree, tvb, headerStart, headerLen,
1704                        "Unsupported Header (0x%02X)", headerType);
1705         return offset;
1706 }
1707
1708 static int
1709 add_application_header (proto_tree *tree, tvbuff_t *tvb, int offset)
1710 {
1711         int startOffset;
1712         guint tokenSize;
1713         const guint8 *token;
1714         value_type_t valueType;
1715         int subvalueLen;
1716         int subvalueOffset;
1717         guint secs;
1718         nstime_t timeValue;
1719         int asvOffset;
1720         guint stringSize;
1721
1722         startOffset = offset;
1723         tokenSize = tvb_strsize (tvb, startOffset);
1724         token = tvb_get_ptr (tvb, startOffset, tokenSize);
1725         offset += tokenSize;
1726
1727         /*
1728          * Special case header "X-WAP.TOD" that is sometimes followed
1729          * by a 4-byte date value.
1730          *
1731          * XXX - according to the 4-May-2000 WSP spec, X-Wap-Tod is
1732          * encoded as a well known header, with a code of 0x3F.
1733          */
1734         if (tokenSize == 10 && strncasecmp ("x-wap.tod", token, 9) == 0)
1735         {
1736                 valueType = get_value_type_len (tvb, offset,
1737                     &subvalueLen, &subvalueOffset, &offset);
1738                 if (get_integer (tvb, subvalueOffset, subvalueLen,
1739                     valueType, &secs) == 0)
1740                 {
1741                         /*
1742                          * Fill in the "struct timeval", and add it to the
1743                          * protocol tree.
1744                          * Note: this will succeed even if it's a Short-integer.
1745                          * A Short-integer would work, but, as the time values
1746                          * are UNIX seconds-since-the-Epoch value, and as
1747                          * there weren't WAP phones or Web servers back in
1748                          * late 1969/early 1970, they're unlikely to be used.
1749                          */
1750                         timeValue.secs = secs;
1751                         timeValue.nsecs = 0;
1752                         proto_tree_add_time (tree, hf_wsp_header_x_wap_tod,
1753                             tvb, startOffset, offset - startOffset, &timeValue);
1754                 }
1755                 else
1756                 {
1757                         proto_tree_add_text (tree, tvb, startOffset,
1758                             offset - startOffset,
1759                             "%s: invalid date value", token);
1760                 }
1761         }
1762         else
1763         {
1764                 asvOffset = offset;
1765                 stringSize = tvb_strsize (tvb, asvOffset);
1766                 offset += stringSize;
1767                 proto_tree_add_text (tree, tvb, startOffset,
1768                     offset - startOffset,
1769                     "%s: %s", token,
1770                     tvb_get_ptr (tvb, asvOffset, stringSize));
1771         }
1772         return offset;
1773 }
1774
1775 static void
1776 add_accept_header (proto_tree *tree, tvbuff_t *header_buff,
1777     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
1778     int valueLen)
1779 {
1780         guint contentType;
1781         const char *contentTypeStr;
1782
1783         add_content_type_value (tree, header_buff, 0, headerLen, value_buff,
1784             valueType, valueLen, hf_wsp_header_accept,
1785             hf_wsp_header_accept_str, &contentType, &contentTypeStr);
1786 }
1787
1788 static void
1789 add_accept_xxx_header (proto_tree *tree, tvbuff_t *header_buff,
1790     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
1791     int valueLen, int hf_numeric, int hf_string,
1792     const value_string *vals, const char *unknown_tag)
1793 {
1794         int offset = 0;
1795         int subvalueLen;
1796         int subvalueOffset;
1797         guint value = 0;
1798         char valString[100];
1799         const char *valMatch;
1800         guint peek;
1801         double q_value = 1.0;
1802
1803         if (valueType == VALUE_IN_LEN)
1804         {
1805                 /*
1806                  * Constrained-{charset,language} (Short-Integer).
1807                  */
1808                 proto_tree_add_uint (tree, hf_numeric,
1809                     header_buff, 0, headerLen,
1810                     valueLen);  /* valueLen is the value */
1811                 return;
1812         }
1813         if (valueType == VALUE_IS_TEXT_STRING)
1814         {
1815                 /*
1816                  * Constrained-{charset,language} (text, i.e.
1817                  * Extension-Media).
1818                  */
1819                 proto_tree_add_string (tree, hf_string,
1820                     header_buff, 0, headerLen,
1821                     tvb_get_ptr (value_buff, 0, valueLen));
1822                 return;
1823         }
1824
1825         /*
1826          * First byte had the 8th bit set.
1827          */
1828         if (valueLen == 0) {
1829                 /*
1830                  * Any-{charset,language}.
1831                  */
1832                 proto_tree_add_string (tree, hf_string,
1833                         header_buff, 0, headerLen,
1834                         "*");
1835                 return;
1836         }
1837
1838         /*
1839          * Accept-{charset,language}-general-form; Value-length, followed
1840          * by Well-known-{charset,language} or {Token-text,Text-string},
1841          * possibly followed by a Q-value.
1842          * 
1843          * Get Value-length.
1844          */
1845         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
1846             &subvalueOffset, &offset);
1847         if (valueType == VALUE_IS_TEXT_STRING)
1848         {
1849                 /*
1850                  * {Token-text,Text-string}.
1851                  */
1852                 valMatch =
1853                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen);
1854                 proto_tree_add_string (tree, hf_string,
1855                         value_buff, 0, valueLen, valMatch);
1856         } else {
1857                 /*
1858                  * Well-known-{charset,langugage}; starts with an
1859                  * Integer-value.
1860                  */
1861                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
1862                     valueType, &value) < 0)
1863                 {
1864                         valMatch = "Invalid integer";
1865                 }
1866                 else
1867                 {
1868                         valMatch = val_to_str(value, vals, unknown_tag);
1869                 }
1870         }
1871
1872         /* Any remaining data relates to Q-value */
1873         if (offset < valueLen)
1874         {
1875                 peek = tvb_get_guintvar (value_buff, offset, NULL);
1876                 if (peek <= 100) {
1877                         peek = (peek - 1) * 10;
1878                 }
1879                 else {
1880                         peek -= 100;
1881                 }
1882                 q_value = peek/1000.0;
1883         }
1884
1885         /* Build string including Q-value if present */
1886         if (q_value == 1.0)                     /* Default */
1887         {
1888                 snprintf (valString, 100, "%s", valMatch);
1889         }
1890         else
1891         {
1892                 snprintf (valString, 100, "%s; Q=%5.3f", valMatch, q_value);
1893         }
1894         /* Add string to tree */
1895         proto_tree_add_string (tree, hf_string,
1896             header_buff, 0, headerLen, valString);
1897 }
1898
1899 static void
1900 add_accept_ranges_header (proto_tree *tree, tvbuff_t *header_buff,
1901     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
1902     int valueLen)
1903 {
1904         if (valueType == VALUE_IN_LEN)
1905         {
1906                 /*
1907                  * Must be 0 (None) or 1 (Bytes) (the 8th bit was stripped
1908                  * off).
1909                  */
1910                 proto_tree_add_uint (tree, hf_wsp_header_accept_ranges,
1911                     header_buff, 0, headerLen,
1912                     valueLen);  /* valueLen is the value */
1913                 return;
1914         }
1915         if (valueType == VALUE_IS_TEXT_STRING)
1916         {
1917                 /*
1918                  * Token-text.
1919                  */
1920                 proto_tree_add_string (tree, hf_wsp_header_accept_ranges_str,
1921                     header_buff, 0, headerLen,
1922                     tvb_get_ptr (value_buff, 0, valueLen));
1923                 return;
1924         }
1925
1926         /*
1927          * Not valid.
1928          */
1929         fprintf(stderr, "dissect_wsp: Accept-Ranges is neither None, Bytes, nor Token-text\n");
1930         return;
1931 }
1932
1933 static void
1934 add_cache_control_header (proto_tree *tree, tvbuff_t *header_buff,
1935     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
1936     int valueLen)
1937 {
1938         int offset = 0;
1939         int subvalueLen;
1940         int subvalueOffset;
1941         guint value;
1942         proto_item *ti;
1943         proto_tree *parameter_tree;
1944         proto_tree *field_names_tree;
1945         guint delta_secs;
1946
1947         if (valueType == VALUE_IN_LEN)
1948         {
1949                 /*
1950                  * No-cache, No-store, Max-age, Max-stale, Min-fresh,
1951                  * Only-if-cached, Public, Private, No-transform,
1952                  * Must-revalidate, Proxy-revalidate, or S-maxage.
1953                  */
1954                 proto_tree_add_uint (tree, hf_wsp_header_cache_control,
1955                     header_buff, 0, headerLen,
1956                     valueLen);  /* valueLen is the value */
1957                 return;
1958         }
1959         if (valueType == VALUE_IS_TEXT_STRING)
1960         {
1961                 /*
1962                  * Cache-extension.
1963                  */
1964                 proto_tree_add_string (tree, hf_wsp_header_cache_control_str,
1965                     header_buff, 0, headerLen,
1966                     tvb_get_ptr (value_buff, 0, valueLen));
1967                 return;
1968         }
1969
1970         /*
1971          * Value-length Cache-directive.
1972          * Get first field of Cache-directive.
1973          */
1974         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
1975             &subvalueOffset, &offset);
1976         if (valueType == VALUE_IS_TEXT_STRING)
1977         {
1978                 /*
1979                  * Cache-extension Parameter.
1980                  */
1981                 ti = proto_tree_add_string (tree, hf_wsp_header_cache_control_str,
1982                     header_buff, 0, headerLen,
1983                     tvb_get_ptr (value_buff, 0, valueLen));
1984                 parameter_tree = proto_item_add_subtree (ti,
1985                     ett_header_cache_control_parameters);
1986
1987                 /*
1988                  * Process the rest of the value as parameters.
1989                  */
1990                 while (tvb_reported_length_remaining (value_buff, offset) > 0) {
1991                         offset = add_parameter (parameter_tree, value_buff,
1992                             offset);
1993                 }
1994                 return;
1995         }
1996         if (get_integer (value_buff, subvalueOffset, subvalueLen, valueType,
1997             &value) < 0)
1998         {
1999                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2000                     "Invalid Cache-Control Cache-directive value");
2001         }
2002         else
2003         {
2004                 switch (value) {
2005
2006                 case NO_CACHE:
2007                 case PRIVATE:
2008                         /*
2009                          * Loop, processing Field-names.
2010                          */
2011                         ti = proto_tree_add_uint (tree,
2012                             hf_wsp_header_cache_control,
2013                             header_buff, 0, headerLen,
2014                             value);
2015                         field_names_tree = proto_item_add_subtree (ti,
2016                             ett_header_cache_control_field_names);
2017                         while (tvb_reported_length_remaining (value_buff, offset)
2018                             > 0) {
2019                                 offset = add_cache_control_field_name (tree,
2020                                     value_buff, offset, value);
2021                         }
2022                         break;
2023
2024                 case MAX_AGE:
2025                 case MAX_STALE:
2026                 case MIN_FRESH:
2027                 case S_MAXAGE:
2028                         /*
2029                          * Get Delta-second-value.
2030                          */
2031                         valueType = get_value_type_len (value_buff, offset,
2032                             &subvalueLen, &subvalueOffset, &offset);
2033                         if (get_integer (value_buff, subvalueOffset,
2034                             subvalueLen, valueType, &delta_secs) < 0)
2035                         {
2036                                 proto_tree_add_text (tree,
2037                                     header_buff, 0, headerLen,
2038                                     "Invalid Cache-Control %s Delta-second-value",
2039                                     match_strval (value, vals_cache_control));
2040                         }
2041                         else 
2042                         {
2043                                 proto_tree_add_uint_format (tree,
2044                                     hf_wsp_header_cache_control,
2045                                     header_buff, 0, headerLen,
2046                                     value,
2047                                     "Cache-Control: %s %u secs",
2048                                     match_strval (value, vals_cache_control),
2049                                     delta_secs);
2050                         }
2051                         break;
2052
2053                 default:
2054                         /*
2055                          * This should not happen, but handle it anyway.
2056                          */
2057                         proto_tree_add_uint (tree,
2058                             hf_wsp_header_cache_control,
2059                             header_buff, 0, headerLen,
2060                             value);
2061                         break;
2062                 }
2063         }
2064 }
2065
2066 static int
2067 add_cache_control_field_name (proto_tree *tree, tvbuff_t *value_buff,
2068     int offset, guint cache_control_value)
2069 {
2070         value_type_t valueType;
2071         int startOffset;
2072         int subvalueLen;
2073         int subvalueOffset;
2074
2075         startOffset = offset;
2076         valueType = get_value_type_len (value_buff, offset,
2077             &subvalueLen, &subvalueOffset, &offset);
2078         if (valueType == VALUE_IS_TEXT_STRING)
2079         {
2080                 /*
2081                  * Token-text.
2082                  */
2083                 proto_tree_add_item (tree, 
2084                     hf_wsp_header_cache_control_field_name_str,
2085                     value_buff, startOffset, offset - startOffset,
2086                     bo_little_endian);
2087         }
2088         else if (valueType == VALUE_IN_LEN)
2089         {
2090                 /*
2091                  * Short-integer Field-name.
2092                  */
2093                 proto_tree_add_uint (tree,
2094                     hf_wsp_header_cache_control_field_name,
2095                     value_buff, startOffset, offset - startOffset,
2096                     subvalueLen);
2097         }
2098         else
2099         {
2100                 /*
2101                  * Long-integer - illegal.
2102                  */
2103                 proto_tree_add_text (tree,
2104                     value_buff, startOffset, offset - startOffset,
2105                     "Invalid Cache-Control %s Field-name",
2106                     match_strval (cache_control_value, vals_cache_control));
2107         }       
2108         return offset;
2109 }
2110
2111 static void
2112 add_connection_header (proto_tree *tree, tvbuff_t *header_buff,
2113     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2114     int valueLen)
2115 {
2116         int offset = 0;
2117
2118         if (valueType == VALUE_LEN_SUPPLIED)
2119         {
2120                 /*
2121                  * Invalid.
2122                  */
2123                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2124                     "Invalid Connection value");
2125                 return;
2126         }
2127         if (valueType == VALUE_IS_TEXT_STRING)
2128         {
2129                 /*
2130                  * Token-text.
2131                  */
2132                 proto_tree_add_string (tree,
2133                     hf_wsp_header_connection_str,
2134                     header_buff, 0, headerLen,
2135                     tvb_get_ptr (value_buff, 0, valueLen));
2136                 return;
2137         }
2138
2139         /*
2140          * First byte had the 8th bit set.
2141          */
2142         if (valueLen == 0) {
2143                 /*
2144                  * Close.
2145                  */
2146                 proto_tree_add_uint (tree, hf_wsp_header_connection,
2147                     header_buff, offset, headerLen, valueLen);
2148                 return;
2149         }
2150
2151         /*
2152          * Invalid.
2153          */
2154         proto_tree_add_text (tree, header_buff, 0, headerLen,
2155             "Invalid Connection value");
2156 }
2157
2158 static void
2159 add_pragma_header (proto_tree *tree, tvbuff_t *header_buff,
2160     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2161     int valueLen)
2162 {
2163         int offset = 0;
2164         int subvalueLen;
2165         int subvalueOffset;
2166
2167         if (valueType == VALUE_IN_LEN)
2168         {
2169                 /*
2170                  * Invalid.
2171                  */
2172                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2173                     "Invalid Pragma");
2174                 return;
2175         }
2176         if (valueType == VALUE_IS_TEXT_STRING)
2177         {
2178                 /*
2179                  * Invalid?
2180                  */
2181                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2182                     "Invalid Pragma");
2183                 return;
2184         }
2185
2186         /*
2187          * First byte had the 8th bit set.
2188          */
2189         if (valueLen == 0) {
2190                 /*
2191                  * No-cache.
2192                  */
2193                 proto_tree_add_string (tree, hf_wsp_header_pragma,
2194                     header_buff, 0, headerLen, "No-cache");
2195                 return;
2196         }
2197
2198         /*
2199          * Value-length, followed by Parameter.
2200          * 
2201          * Get Value-length.
2202          */
2203         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
2204             &subvalueOffset, &offset);
2205         if (valueType == VALUE_IS_TEXT_STRING)
2206         {
2207                 /*
2208                  * Parameter - a text string.
2209                  */
2210                 proto_tree_add_string (tree, hf_wsp_header_pragma,
2211                     header_buff, 0, headerLen,
2212                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
2213         } else {
2214                 /*
2215                  * Parameter - numeric; illegal?
2216                  */
2217                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2218                     "Invalid Pragma");
2219         }
2220 }
2221
2222 static void
2223 add_transfer_encoding_header (proto_tree *tree, tvbuff_t *header_buff,
2224     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2225     int valueLen)
2226 {
2227         int offset = 0;
2228
2229         if (valueType == VALUE_LEN_SUPPLIED)
2230         {
2231                 /*
2232                  * Invalid.
2233                  */
2234                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2235                     "Invalid Transfer-Encoding value");
2236                 return;
2237         }
2238         if (valueType == VALUE_IS_TEXT_STRING)
2239         {
2240                 /*
2241                  * Token-text.
2242                  */
2243                 proto_tree_add_string (tree,
2244                     hf_wsp_header_transfer_encoding_str,
2245                     header_buff, 0, headerLen,
2246                     tvb_get_ptr (value_buff, 0, valueLen));
2247                 return;
2248         }
2249
2250         /*
2251          * First byte had the 8th bit set.
2252          */
2253         if (valueLen == 0) {
2254                 /*
2255                  * Chunked.
2256                  */
2257                 proto_tree_add_uint (tree, hf_wsp_header_transfer_encoding,
2258                     header_buff, offset, headerLen, valueLen);
2259                 return;
2260         }
2261
2262         /*
2263          * Invalid.
2264          */
2265         proto_tree_add_text (tree, header_buff, 0, headerLen,
2266             "Invalid Transfer Encoding value");
2267 }
2268
2269 static void
2270 add_warning_header (proto_tree *tree, tvbuff_t *header_buff,
2271     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2272     int valueLen)
2273 {
2274         int offset = 0;
2275         proto_item *ti;
2276         proto_tree *warning_tree;
2277         int subvalueLen;
2278         int subvalueOffset;
2279
2280         /*
2281          * Put the items under a header.
2282          * XXX - make the text of the item summarize the elements.
2283          */
2284         ti = proto_tree_add_item (tree, hf_wsp_header_warning,
2285             header_buff, 0, headerLen, bo_little_endian);
2286         warning_tree = proto_item_add_subtree(ti, ett_header_warning);
2287         
2288         if (valueType == VALUE_IN_LEN)
2289         {
2290                 /*
2291                  * Warn-code (Short-integer).
2292                  */
2293                 proto_tree_add_uint (warning_tree, hf_wsp_header_warning_code,
2294                     header_buff, 0, headerLen,
2295                     valueLen);  /* valueLen is the value */
2296                 return;
2297         }
2298         if (valueType == VALUE_IS_TEXT_STRING)
2299         {
2300                 /*
2301                  * Invalid.
2302                  */
2303                 proto_tree_add_text (warning_tree, header_buff, 0, headerLen,
2304                     "Invalid Warning (all text)");
2305                 return;
2306         }
2307
2308         /*
2309          * Warning-value; Warn-code, followed by Warn-agent, followed by
2310          * Warn-text.
2311          */
2312         /*
2313          * Get Short-integer Warn-code.
2314          */
2315         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2316             &subvalueOffset, &offset);
2317         if (valueType != VALUE_IN_LEN)
2318         {
2319                 /*
2320                  * Not a Short-integer.
2321                  */
2322                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2323                     subvalueLen, "Invalid Warn-code (not a Short-integer)");
2324                 return;
2325         }
2326         proto_tree_add_uint (warning_tree, hf_wsp_header_warning_code,
2327             value_buff, subvalueOffset, 1,
2328             subvalueLen);       /* subvalueLen is the value */
2329
2330         /*
2331          * Warn-agent; must be text.
2332          */
2333         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2334             &subvalueOffset, &offset);
2335         if (valueType != VALUE_IS_TEXT_STRING)
2336         {
2337                 /*
2338                  * Not text.
2339                  */
2340                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2341                     subvalueLen, "Invalid Warn-agent (not a text string)");
2342                 return;
2343         }
2344         proto_tree_add_item (warning_tree,
2345                 hf_wsp_header_warning_agent,
2346                 value_buff, subvalueOffset, subvalueLen, bo_little_endian);
2347
2348         /*
2349          * Warn-text; must be text.
2350          */
2351         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2352             &subvalueOffset, &offset);
2353         if (valueType != VALUE_IS_TEXT_STRING)
2354         {
2355                 /*
2356                  * Not text.
2357                  */
2358                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2359                     subvalueLen, "Invalid Warn-text (not a text string)");
2360                 return;
2361         }
2362         proto_tree_add_item (warning_tree,
2363                 hf_wsp_header_warning_text,
2364                 value_buff, subvalueOffset, subvalueLen, bo_little_endian);
2365 }
2366
2367 static void
2368 add_accept_application_header (proto_tree *tree, tvbuff_t *header_buff,
2369     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2370     int valueLen)
2371 {
2372         guint value;
2373
2374         if (valueType == VALUE_IN_LEN)
2375         {
2376                 /*
2377                  * Application-id-value; numeric, so it's App-assigned-code.
2378                  */
2379                 proto_tree_add_uint (tree, hf_wsp_header_accept_application,
2380                     header_buff, 0, headerLen,
2381                     valueLen);  /* valueLen is the value */
2382                 return;
2383         }
2384         if (valueType == VALUE_IS_TEXT_STRING)
2385         {
2386                 /*
2387                  * Uri-value.
2388                  */
2389                 proto_tree_add_string (tree, hf_wsp_header_accept_application_str,
2390                     header_buff, 0, headerLen,
2391                     tvb_get_ptr (value_buff, 0, valueLen));
2392                 return;
2393         }
2394
2395         /*
2396          * First byte had the 8th bit set.
2397          */
2398         if (valueLen == 0) {
2399                 /*
2400                  * Any-application.
2401                  */
2402                 proto_tree_add_string (tree, hf_wsp_header_accept_application_str,
2403                         header_buff, 0, headerLen,
2404                         "*");
2405                 return;
2406         }
2407
2408         /*
2409          * Integer-value, hence App-assigned-code.
2410          */
2411         if (get_integer (value_buff, 0, valueLen, valueType, &value) < 0)
2412         {
2413                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2414                         "Invalid Accept-Application App-assigned-code");
2415         }
2416         else
2417         {
2418                 proto_tree_add_uint (tree, hf_wsp_header_accept_application,
2419                     header_buff, 0, headerLen, value);
2420         }
2421 }
2422
2423 static void
2424 add_wap_application_id_header (proto_tree *tree, tvbuff_t *header_buff,
2425     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2426     int valueLen)
2427 {
2428         if (valueType == VALUE_IN_LEN)
2429         {
2430                 /*
2431                  * Must application-id (the 8th bit was stripped off).
2432                  */
2433                 proto_tree_add_uint (tree, hf_wsp_header_wap_application_id,
2434                     header_buff, 0, headerLen,
2435                     valueLen);  /* valueLen is the value */
2436                 return;
2437         }
2438         if (valueType == VALUE_IS_TEXT_STRING)
2439         {
2440                 /*
2441                  * Token-text.
2442                  */
2443                 proto_tree_add_string (tree, hf_wsp_header_wap_application_id_str,
2444                     header_buff, 0, headerLen,
2445                     tvb_get_ptr (value_buff, 0, valueLen));
2446                 return;
2447         }
2448
2449         /*
2450          * Not valid.
2451          */
2452         fprintf(stderr, "dissect_wsp: Suprising format of X-Wap-Application-Id\n");
2453         return;
2454 }
2455
2456 static void
2457 add_capabilities (proto_tree *tree, tvbuff_t *tvb, int type)
2458 {
2459         proto_item *ti;
2460         proto_tree *wsp_capabilities;
2461         guint offset = 0;
2462         guint offsetStr = 0;
2463         guint capabilitiesLen = tvb_reported_length (tvb);
2464         guint capabilitiesStart = 0;
2465         guint peek = 0;
2466         guint length = 0;
2467         guint value = 0;
2468         guint i;
2469         int ret;
2470         char valString[200];
2471
2472 #ifdef DEBUG
2473         fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, capabilitiesLen);
2474 #endif
2475
2476         /* End of buffer */
2477         if (capabilitiesLen <= 0)
2478         {
2479                 fprintf (stderr, "dissect_wsp: Capabilities = 0\n");
2480                 return;
2481         }
2482
2483 #ifdef DEBUG
2484         fprintf (stderr, "dissect_wsp: capabilities to process\n");
2485 #endif
2486
2487         ti = proto_tree_add_item (tree, hf_wsp_capabilities_section,tvb,offset,capabilitiesLen,bo_little_endian);
2488         wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
2489
2490         /* Parse Headers */
2491
2492         while (offset < capabilitiesLen)
2493         {
2494                 /* Loop round each header */
2495                 capabilitiesStart = offset;
2496                 length = tvb_get_guint8 (tvb, capabilitiesStart);
2497
2498                 if (length >= 127)              /* length */
2499                 {
2500 #ifdef DEBUG
2501                         fprintf (stderr, "dissect_wsp: capabilities length invalid %d\n",length);
2502 #endif
2503                         offset+=length;
2504                         continue;
2505                 }
2506                 offset++;
2507                 peek = tvb_get_guint8 (tvb, offset);
2508                 offset++;
2509                 switch (peek & 0x7f)
2510                 {
2511                         case 0x00 : /* Client-SDU-Size */
2512                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2513                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_client_SDU, tvb, capabilitiesStart, length+1, value);
2514                                 break;
2515                         case 0x01 : /* Server-SDU-Size */
2516                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2517                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_server_SDU, tvb, capabilitiesStart, length+1, value);
2518                                 break;
2519                         case 0x02 : /* Protocol Options */ 
2520                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2521                                 i = 0;
2522                                 valString[0]=0;
2523                                 if (value & 0x80)
2524                                 {
2525                                         ret = snprintf(valString+i,200-i,"%s","(Confirmed push facility) ");
2526                                         if (ret == -1) {
2527                                                 /*
2528                                                  * Some versions of snprintf
2529                                                  * return -1 if they'd
2530                                                  * truncate the output.
2531                                                  */
2532                                                 goto add_string;
2533                                         }
2534                                         i += ret;
2535                                 }
2536                                 if (value & 0x40)
2537                                 {
2538                                         if (i >= 200) {
2539                                                 /* No more room. */
2540                                                 goto add_string;
2541                                         }
2542                                         ret = snprintf(valString+i,200-i,"%s","(Push facility) ");
2543                                         if (ret == -1) {
2544                                                 /*
2545                                                  * Some versions of snprintf
2546                                                  * return -1 if they'd
2547                                                  * truncate the output.
2548                                                  */
2549                                                 goto add_string;
2550                                         }
2551                                         i += ret;
2552                                 }
2553                                 if (value & 0x20)
2554                                 {
2555                                         if (i >= 200) {
2556                                                 /* No more room. */
2557                                                 goto add_string;
2558                                         }
2559                                         ret = snprintf(valString+i,200-i,"%s","(Session resume facility) ");
2560                                         if (ret == -1) {
2561                                                 /*
2562                                                  * Some versions of snprintf
2563                                                  * return -1 if they'd
2564                                                  * truncate the output.
2565                                                  */
2566                                                 goto add_string;
2567                                         }
2568                                         i += ret;
2569                                 }
2570                                 if (value & 0x10)
2571                                 {
2572                                         if (i >= 200) {
2573                                                 /* No more room. */
2574                                                 goto add_string;
2575                                         }
2576                                         ret = snprintf(valString+i,200-i,"%s","(Acknowledgement headers) ");
2577                                         if (ret == -1) {
2578                                                 /*
2579                                                  * Some versions of snprintf
2580                                                  * return -1 if they'd
2581                                                  * truncate the output.
2582                                                  */
2583                                                 goto add_string;
2584                                         }
2585                                         i += ret;
2586                                 }
2587                         add_string:
2588                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_protocol_opt, tvb, capabilitiesStart, length+1, valString);
2589                                 break;
2590                         case 0x03 : /* Method-MOR */ 
2591                                 value = tvb_get_guint8(tvb, offset);
2592                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_method_MOR, tvb, capabilitiesStart, length+1, value);
2593                                 break;
2594                         case 0x04 : /* Push-MOR */ 
2595                                 value = tvb_get_guint8(tvb, offset);
2596                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_push_MOR, tvb, capabilitiesStart, length+1, value);
2597                                 break;
2598                                 break;
2599                         case 0x05 : /* Extended Methods */ 
2600                                 offsetStr = offset;
2601                                 offset++;
2602                                 add_capability_vals(tvb, (type == CONNECT),
2603                                     offsetStr, length, capabilitiesStart,
2604                                     valString, sizeof valString);
2605                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_extended_methods, tvb, capabilitiesStart, length+1, valString);
2606                                 break;
2607                         case 0x06 : /* Header Code Pages */ 
2608                                 offsetStr = offset;
2609                                 offset++;
2610                                 add_capability_vals(tvb, (type == CONNECT),
2611                                     offsetStr, length, capabilitiesStart,
2612                                     valString, sizeof valString);
2613                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_header_code_pages, tvb, capabilitiesStart, length+1, valString);
2614                                 break;
2615                         case 0x07 : /* Aliases */
2616                                 break;
2617                         default:
2618                                 proto_tree_add_text (wsp_capabilities, tvb , capabilitiesStart, length+1,
2619                                        "Unsupported Header (0x%02X)", peek & 0x7F);
2620                                 break;
2621                 }
2622                 offset=capabilitiesStart+length+1;
2623         }
2624 }
2625
2626 static void
2627 add_capability_vals(tvbuff_t *tvb, gboolean add_string, int offsetStr,
2628     guint length, guint capabilitiesStart, char *valString,
2629     size_t valStringSize)
2630 {
2631         guint i;
2632         int ret;
2633         guint value;
2634         guint8 c;
2635
2636         i = 0;
2637         while ((offsetStr-capabilitiesStart) <= length)
2638         {
2639                 value = tvb_get_guint8(tvb, offsetStr);
2640                 if (i >= valStringSize) {
2641                         /* No more room. */
2642                         break;
2643                 }
2644                 if (add_string)
2645                 {
2646                         ret = snprintf(valString+i,valStringSize-i,
2647                             "(%d - ",value);
2648                 }
2649                 else
2650                 {
2651                         ret = snprintf(valString+i,valStringSize-i,"(%d) ",
2652                             value);
2653                 }
2654                 if (ret == -1) {
2655                         /*
2656                          * Some versions of snprintf return -1
2657                          * if they'd truncate the output.
2658                          */
2659                         break;
2660                 }
2661                 i += ret;
2662                 offsetStr++;
2663                 if (add_string)
2664                 {
2665                         for (;(c = tvb_get_guint8(tvb, offsetStr))
2666                             && i < valStringSize - 1; i++,offsetStr++)
2667                                 valString[i] = c;
2668                         offsetStr++;
2669                         if (i < valStringSize - 2) {
2670                                 valString[i++] = ')';
2671                                 valString[i++] = ' ';
2672                         }
2673                 }
2674         }
2675         valString[i] = '\0';
2676 }
2677
2678 static value_type_t
2679 get_value_type_len (tvbuff_t *tvb, int offset, guint *valueLen,
2680     int *valueOffset, int *nextOffset)
2681 {
2682         guint8 peek;
2683         guint32 len;
2684         guint count;
2685
2686         /* Get value part of header */
2687         peek = tvb_get_guint8 (tvb, offset);
2688         if (peek <= 30)
2689         {
2690                 /*
2691                  * The value follows "peek", and is "peek" octets long.
2692                  */
2693 #ifdef DEBUG
2694                 fprintf (stderr, "dissect_wsp: Looking for %d octets\n", peek);
2695 #endif
2696                 len = peek;
2697                 *valueLen = len;        /* Length of value */
2698                 offset++;               /* Skip the length */
2699                 *valueOffset = offset;  /* Offset of value */
2700                 offset += len;          /* Skip the value */
2701                 *nextOffset = offset;   /* Offset after value */
2702                 return VALUE_LEN_SUPPLIED;
2703         }
2704         else if (peek == 31)
2705         {
2706                 /*
2707                  * A uintvar giving the length of the value follows
2708                  * "peek", and the value follows that.
2709                  */
2710 #ifdef DEBUG
2711                 fprintf (stderr, "dissect_wsp: Looking for uintvar octets\n");
2712 #endif
2713                 offset++;               /* Skip the uintvar indicator */
2714                 count = 0;              /* Initialise count */
2715                 len = tvb_get_guintvar (tvb, offset, &count);
2716                 *valueLen = len;        /* Length of value */
2717                 offset += count;        /* Skip the length */
2718                 *valueOffset = offset;  /* Offset of value */
2719                 offset += len;          /* Skip the value */
2720                 *nextOffset = offset;   /* Offset after value */
2721                 return VALUE_LEN_SUPPLIED;
2722         }
2723         else if (peek <= 127)
2724         {
2725                 /*
2726                  * The value is a NUL-terminated string, and "peek"
2727                  * is the first octet of the string.
2728                  */
2729 #ifdef DEBUG
2730                 fprintf (stderr, "dissect_wsp: Looking for NUL-terminated string\n");
2731 #endif
2732                 len = tvb_strsize (tvb, offset);
2733                 *valueLen = len;        /* Length of value */
2734                 *valueOffset = offset;  /* Offset of value */
2735                 offset += len;          /* Skip the value */
2736                 *nextOffset = offset;   /* Offset after value */
2737                 return VALUE_IS_TEXT_STRING;
2738         }
2739         else
2740         {
2741                 /*
2742                  * "peek", with the 8th bit stripped off, is the value.
2743                  */
2744 #ifdef DEBUG
2745                 fprintf (stderr, "dissect_wsp: Value is %d\n", (peek & 0x7F));
2746 #endif
2747                 *valueLen = peek & 0x7F; /* Return the value itself */
2748                 *valueOffset = offset;  /* Offset of value */
2749                 offset++;               /* Skip the value */
2750                 *nextOffset = offset;   /* Offset after value */
2751                 return VALUE_IN_LEN;
2752         }
2753 }
2754
2755 static guint
2756 get_uintvar (tvbuff_t *tvb, guint offset, guint offsetEnd)
2757 {
2758         guint value = 0;
2759         guint octet;
2760
2761         do
2762         {
2763                 octet = tvb_get_guint8 (tvb, offset);
2764                 offset++;
2765                 value <<= 7;
2766                 value += octet & 0x7f;
2767         }
2768         while ((offsetEnd > offset) && (octet & 0x80));
2769         return value;
2770 }
2771
2772 static void
2773 add_content_type_value (proto_tree *tree, tvbuff_t *header_buff,
2774     int headerOffset, int headerLen, tvbuff_t *value_buff,
2775     value_type_t valueType, int valueLen, int hf_numeric, int hf_string,
2776     guint *contentTypep, const char **contentTypeStrp)
2777 {
2778         proto_item *ti;
2779         proto_tree *parameter_tree;
2780         const char *contentTypeStr;
2781         int offset;
2782         int subvalueLen;
2783         int subvalueOffset;
2784         guint value;
2785
2786         if (valueType == VALUE_IN_LEN)
2787         {
2788                 /*
2789                  * Constrained-media (Short-Integer).
2790                  */
2791                 proto_tree_add_uint (tree, hf_numeric,
2792                     header_buff, headerOffset, headerLen,
2793                     valueLen);  /* valueLen is the value */
2794
2795                 /*
2796                  * Return the numerical value, and a null string value
2797                  * indicating that the value is numerical.
2798                  */
2799                 *contentTypep = valueLen;
2800                 *contentTypeStrp = NULL;
2801                 return;
2802         }
2803         if (valueType == VALUE_IS_TEXT_STRING)
2804         {
2805                 /*
2806                  * Constrained-media (text, i.e. Extension-Media).
2807                  */
2808                 contentTypeStr = tvb_get_ptr (value_buff, 0, valueLen);
2809                 proto_tree_add_string (tree, hf_string,
2810                     header_buff, headerOffset, headerLen,
2811                     contentTypeStr);
2812
2813                 /*
2814                  * Return the string value, and set the numerical value
2815                  * to 0 (as it shouldn't be used).
2816                  */
2817                 *contentTypep = 0;
2818                 *contentTypeStrp = contentTypeStr;
2819                 return;
2820         }
2821
2822         /*
2823          * Content-general-form; Value-length, followed by Media-range,
2824          * followed by optional Accept-parameters.
2825          *
2826          * Get Value-length.
2827          */
2828         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
2829             &subvalueOffset, &offset);
2830         if (valueType == VALUE_IS_TEXT_STRING)
2831         {
2832                 /*
2833                  * Extension-Media; value is a string.
2834                  */
2835                 contentTypeStr =
2836                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen);
2837                 ti = proto_tree_add_string (tree, hf_string, header_buff,
2838                     headerOffset, headerLen, contentTypeStr);
2839
2840                 /*
2841                  * Return the string value, and set the numerical value
2842                  * to 0 (as it shouldn't be used).
2843                  */
2844                 *contentTypep = 0;
2845                 *contentTypeStrp = contentTypeStr;
2846         }
2847         else
2848         {
2849                 /*
2850                  * Well-known-media; value is an Integer.
2851                  */
2852                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
2853                     valueType, &value) < 0)
2854                 {
2855                         proto_tree_add_text (tree, header_buff,
2856                             headerOffset, headerLen,
2857                             "Invalid integer for Well-known-media");
2858
2859                         /*
2860                          * Content type is invalid.
2861                          * Don't try to parse the rest of the value.
2862                          */
2863                         *contentTypep = 0;
2864                         *contentTypeStrp = NULL;
2865                         return;
2866                 }
2867                 ti = proto_tree_add_uint (tree, hf_numeric,
2868                     header_buff, headerOffset, headerLen, value);
2869
2870                 /*
2871                  * Return the numerical value, and a null string value
2872                  * indicating that the value is numerical.
2873                  */
2874                 *contentTypep = value;
2875                 *contentTypeStrp = NULL;
2876         }
2877
2878         /*
2879          * Process the rest of the value as parameters.
2880          */
2881         parameter_tree = proto_item_add_subtree(ti,
2882             ett_content_type_parameters);
2883         while (tvb_reported_length_remaining (value_buff, offset) > 0)
2884                 offset = add_parameter (parameter_tree, value_buff, offset);
2885 }
2886
2887 guint
2888 add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset,
2889     guint *contentTypep, const char **contentTypeStrp)
2890 {
2891         int valueStart;
2892         value_type_t valueType;
2893         int valueTypeLen;
2894         guint valueLen;
2895         int valueOffset;
2896         tvbuff_t *value_buff;
2897
2898         valueStart = offset;
2899
2900         /*
2901          * Get the value type and length (or, if the type is VALUE_IN_LEN,
2902          * meaning the value is a Short-integer, get the value type
2903          * and the value itself).
2904          */ 
2905         valueType = get_value_type_len (tvb, valueStart, &valueLen,
2906             &valueOffset, &offset);
2907         valueTypeLen = offset - valueStart;
2908
2909         /*
2910          * Get a tvbuff for the value.
2911          * XXX - can valueLen be 0?
2912          * XXX - cut the actual length short so that it doesn't run
2913          * past the actual length of tvb.
2914          */
2915         if (valueType != VALUE_IN_LEN) {
2916                 value_buff = tvb_new_subset (tvb, valueOffset, valueLen,
2917                     valueLen);
2918         } else {
2919                 /*
2920                  * XXX - when the last dissector is tvbuffified,
2921                  * so that NULL is no longer a valid tvb pointer
2922                  * value in "proto_tree_add" calls, just
2923                  * set "value_buff" to NULL.
2924                  *
2925                  * XXX - can we already do that?  I.e., will that
2926                  * cause us always to crash if we mistakenly try
2927                  * to fetch the value of a VALUE_IN_LEN item?
2928                  */
2929                 value_buff = tvb_new_subset (tvb, valueStart, 0, 0);
2930         }
2931
2932         add_content_type_value (tree, tvb, valueStart, valueTypeLen, value_buff,
2933             valueType, valueLen, hf_wsp_content_type,
2934             hf_wsp_content_type_str, contentTypep, contentTypeStrp);
2935
2936         return offset;
2937 }
2938
2939 static void
2940 add_integer_value_header (proto_tree *tree, tvbuff_t *header_buff,
2941     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2942     int valueLen, int hf_numeric, guint8 headerType)
2943 {
2944         guint value;
2945
2946         if (get_integer (value_buff, 0, valueLen, valueType, &value) < 0)
2947         {
2948                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2949                     "Invalid %s integer value",
2950                     match_strval (headerType, vals_field_names));
2951         }
2952         else
2953         {
2954                 proto_tree_add_uint (tree, hf_numeric,
2955                     header_buff, 0, headerLen, value);
2956         }
2957 }
2958
2959 static void
2960 add_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
2961     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2962     int valueLen, int hf_string, guint8 headerType)
2963 {
2964         if (valueType != VALUE_IS_TEXT_STRING)
2965         {
2966                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2967                     "Invalid %s string value",
2968                     match_strval (headerType, vals_field_names));
2969         }
2970         else
2971         {
2972                 proto_tree_add_string (tree, hf_string, header_buff,
2973                         0, headerLen, tvb_get_ptr (value_buff, 0, valueLen));
2974         }
2975 }
2976
2977 static void
2978 add_quoted_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
2979     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2980     int valueLen, int hf_string, guint8 headerType)
2981 {
2982         if (valueType != VALUE_IS_TEXT_STRING)
2983         {
2984                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2985                     "Invalid %s quoted string value",
2986                     match_strval (headerType, vals_field_names));
2987         }
2988         else
2989         {
2990                 proto_tree_add_string (tree, hf_string, header_buff,
2991                         0, headerLen, tvb_get_ptr (value_buff, 1, valueLen - 1));
2992         }
2993 }
2994
2995 /* Utility function to add a date value to the protocol tree */
2996 static void
2997 add_date_value_header (proto_tree *tree, tvbuff_t *header_buff,
2998     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2999     int valueLen, int hf_time, guint8 headerType)
3000 {
3001         guint secs;
3002         nstime_t timeValue;
3003
3004         /* Attempt to get the date value from the buffer */
3005         if (get_integer (value_buff, 0, valueLen, valueType, &secs) == 0)
3006         {
3007                 /*
3008                  * Fill in the "struct timeval", and add it to the
3009                  * protocol tree.
3010                  * Note: this will succeed even if it's a Short-integer.
3011                  * A Short-integer would work, but, as the time values
3012                  * are UNIX seconds-since-the-Epoch value, and as
3013                  * there weren't WAP phones or Web servers back in
3014                  * late 1969/early 1970, they're unlikely to be used.
3015                  */
3016                 timeValue.secs = secs;
3017                 timeValue.nsecs = 0;
3018                 proto_tree_add_time (tree, hf_time, header_buff, 0,
3019                         headerLen, &timeValue);
3020         }
3021         else
3022         {
3023                 proto_tree_add_text (tree, header_buff, 0, headerLen,
3024                     "Invalid %s date value",
3025                     match_strval (headerType, vals_field_names));
3026         }
3027 }
3028
3029 static int
3030 add_parameter (proto_tree *tree, tvbuff_t *value_buff, int offset)
3031 {
3032         int startOffset;
3033         value_type_t valueType;
3034         int subvalueLen;
3035         int subvalueOffset;
3036         guint value;
3037
3038         startOffset = offset;
3039         valueType = get_value_type_len (value_buff, offset,
3040             &subvalueLen, &subvalueOffset, &offset);
3041         if (valueType == VALUE_IS_TEXT_STRING)
3042         {
3043                 /*
3044                  * Untyped-parameter.
3045                  */
3046                 offset = add_untyped_parameter (tree, value_buff, startOffset, offset);
3047                 return offset;
3048         }
3049
3050         /*
3051          * Well-known-parameter-token.
3052          */
3053         if (get_integer (value_buff, subvalueOffset,
3054             subvalueLen, valueType, &value) < 0)
3055         {
3056                 proto_tree_add_text (tree, value_buff, startOffset,
3057                     offset - startOffset,
3058                     "Invalid Well-known-parameter-token");
3059                 return offset;
3060         }
3061
3062         switch (value) {
3063
3064         case 0x01:      /* Charset */
3065                 offset = add_parameter_charset (tree, value_buff, startOffset, offset);
3066                 break;
3067
3068         case 0x03:      /* Type */
3069                 offset = add_parameter_type (tree, value_buff, startOffset, offset);
3070                 break;
3071
3072         case 0x05:      /* Name */
3073                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3074                                     hf_wsp_parameter_name, "Name");
3075                 break;
3076
3077         case 0x06:      /* Filename */
3078                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3079                                     hf_wsp_parameter_filename, "Filename");
3080                 break;
3081
3082         case 0x09:      /* Type (special) */
3083                 offset = add_constrained_encoding(tree, value_buff, startOffset, offset);
3084                 break;
3085
3086         case 0x0A:      /* Start */
3087                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3088                                     hf_wsp_parameter_start, "Start");
3089                 break;
3090
3091         case 0x0B:      /* Start-info */
3092                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3093                                     hf_wsp_parameter_start_info, "Start-info");
3094                 break;
3095
3096         case 0x0C:      /* Comment */
3097                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3098                                     hf_wsp_parameter_comment, "Comment");
3099                 break;
3100
3101         case 0x0D:      /* Domain */
3102                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3103                                     hf_wsp_parameter_domain, "Domain");
3104                 break;
3105
3106         case 0x0F:      /* Path */
3107                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3108                                     hf_wsp_parameter_path, "Path");
3109                 break;
3110
3111         case 0x00:      /* Q */
3112         case 0x02:      /* Level */
3113         case 0x07:      /* Differences */
3114         case 0x08:      /* Padding */
3115         case 0x0E:      /* Max-Age */
3116         case 0x10:      /* Secure */
3117         default:
3118                 break;
3119         }
3120
3121         return offset;
3122 }
3123
3124 static int
3125 add_untyped_parameter (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3126     int offset)
3127 {
3128         const guint8 *token;
3129         value_type_t valueType;
3130         int subvalueLen;
3131         int subvalueOffset;
3132         guint value;
3133         int vOffset = offset;
3134
3135         token = tvb_get_ptr (value_buff, startOffset, offset - startOffset);
3136         /*
3137          * Now an Untyped-value; either an Integer-value or a Text-value.
3138          */
3139         valueType = get_value_type_len (value_buff, offset,
3140             &subvalueLen, &subvalueOffset, &offset);
3141         if (valueType == VALUE_IS_TEXT_STRING)
3142         {
3143                 /*
3144                  * Text-value.
3145                  */
3146                 if ((offset - vOffset) == 1) {
3147                         /*
3148                          * No-value.  (stringSize includes the terminating
3149                          * null byte, so an empty string has a size of 1.)
3150                          */
3151                         proto_tree_add_text (tree, value_buff, startOffset,
3152                             offset - startOffset,
3153                             "%s", token);
3154                         return offset;
3155                 }
3156                 proto_tree_add_text (tree, value_buff, startOffset,
3157                     offset - startOffset,
3158                     "%s: %s", token,
3159                     tvb_get_ptr (value_buff, vOffset, offset - vOffset));
3160         }
3161         else
3162         {
3163                 /*
3164                  * Integer-value.
3165                  */
3166                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
3167                     valueType, &value) == 0)
3168                 {
3169                         proto_tree_add_text (tree, value_buff, startOffset,
3170                             offset - startOffset,
3171                             "%s: %u", token, value);
3172                 }
3173                 else
3174                 {
3175                         proto_tree_add_text (tree, value_buff, startOffset,
3176                             offset - startOffset,
3177                             "%s: Invalid Integer-value", token);
3178                 }
3179         }
3180         return offset;
3181 }
3182
3183 static int
3184 add_parameter_charset (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3185     int offset)
3186 {
3187         value_type_t valueType;
3188         int subvalueLen;
3189         int subvalueOffset;
3190         guint value;
3191
3192         valueType = get_value_type_len (value_buff, offset,
3193             &subvalueLen, &subvalueOffset, &offset);
3194         if (valueType == VALUE_IN_LEN)
3195         {
3196                 /*
3197                  * Integer-value.
3198                  */
3199                 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset,
3200                     value_buff, startOffset, offset - startOffset,
3201                     subvalueLen);       /* subvalueLen is the value */
3202                 return offset;
3203         }
3204         if (valueType == VALUE_IS_TEXT_STRING)
3205         {
3206                 /*
3207                  * Invalid.
3208                  */
3209                 proto_tree_add_text (tree, value_buff, startOffset,
3210                     offset - startOffset, "Invalid Well-known charset");
3211                 return offset;
3212         }
3213
3214         /*
3215          * First byte had the 8th bit set.
3216          */
3217         if (subvalueLen == 0) {
3218                 /*
3219                  * Any-charset.
3220                  * XXX - add this as a field?
3221                  */
3222                 proto_tree_add_text (tree, value_buff, startOffset,
3223                     offset- startOffset, "*");
3224                 return offset;
3225         }
3226
3227         if (get_integer(value_buff, subvalueOffset, subvalueLen,
3228             valueType, &value) == -1) {
3229                 proto_tree_add_text (tree, value_buff, startOffset,
3230                     offset - startOffset, "Length %u not handled in Well-known charset",
3231                         subvalueLen);
3232         } else {
3233                 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset,
3234                     value_buff, startOffset, offset - startOffset, value);
3235         }
3236         return offset;
3237 }
3238
3239 static int
3240 add_constrained_encoding (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3241     int offset)
3242 {
3243         value_type_t valueType;
3244         int subvalueLen;
3245         int subvalueOffset;
3246         guint value;
3247
3248         valueType = get_value_type_len (value_buff, offset,
3249             &subvalueLen, &subvalueOffset, &offset);
3250         if (valueType == VALUE_IN_LEN)
3251         {
3252                 /*
3253                  * Integer-value, invalid
3254                  */
3255                 proto_tree_add_text (tree, value_buff, startOffset,
3256                     offset - startOffset, "Invalid multipart type parameter");
3257                 return offset;
3258         }
3259         if (valueType == VALUE_IS_TEXT_STRING)
3260         {
3261                 /*
3262                  * type-label.
3263                  */
3264                 proto_tree_add_string (tree, hf_wsp_parameter_upart_type,
3265                     value_buff, startOffset, offset - startOffset,
3266                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
3267                 return offset;
3268         }
3269         /*
3270          * First byte had the 8th bit set.
3271          */
3272         get_integer(value_buff, subvalueOffset, subvalueLen, valueType, &value);
3273         proto_tree_add_uint (tree, hf_wsp_parameter_upart_type_value,
3274             value_buff, startOffset, offset - startOffset, value);
3275         return offset;
3276 }
3277
3278 static int
3279 add_parameter_type (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3280     int offset)
3281 {
3282         value_type_t valueType;
3283         int subvalueLen;
3284         int subvalueOffset;
3285         guint value;
3286
3287         valueType = get_value_type_len (value_buff, offset,
3288             &subvalueLen, &subvalueOffset, &offset);
3289         if (get_integer(value_buff, subvalueOffset, subvalueLen,
3290             valueType, &value) == -1) {
3291                 proto_tree_add_text (tree, value_buff, startOffset,
3292                     offset - startOffset, "Invalid type");
3293         } else {
3294                 proto_tree_add_uint (tree, hf_wsp_parameter_type, value_buff,
3295                     startOffset, offset - startOffset, value);
3296         }
3297         return offset;
3298 }
3299
3300 static int
3301 add_parameter_text (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3302     int offset, int hf_string, const char *paramName)
3303 {
3304         value_type_t valueType;
3305         int subvalueLen;
3306         int subvalueOffset;
3307
3308         valueType = get_value_type_len (value_buff, offset,
3309             &subvalueLen, &subvalueOffset, &offset);
3310         if (valueType != VALUE_IS_TEXT_STRING) {
3311                 proto_tree_add_text (tree, value_buff, startOffset,
3312                     offset - startOffset, "Invalid %s", paramName);
3313         } else {
3314                 proto_tree_add_string (tree, hf_string, value_buff,
3315                             startOffset, offset - startOffset,
3316                             tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
3317         }
3318         return offset;
3319 }
3320
3321 static void
3322 add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType,
3323     const char *contentTypeStr)
3324 {
3325         guint offset = 0;
3326         guint variableStart = 0;
3327         guint variableEnd = 0;
3328         guint valueStart = 0;
3329         guint valueEnd = 0;
3330         guint8 peek = 0;
3331         proto_item *ti;
3332         
3333         /* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_length_remaining(tvb, offset),bo_little_endian); */
3334         ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_reported_length(tvb),bo_little_endian);
3335
3336         if (contentTypeStr == NULL && contentType == 0x12)
3337         {
3338                 /*
3339                  * URL Encoded data.
3340                  * Iterate through post data.
3341                  */
3342                 for (offset = 0; offset < tvb_reported_length (tvb); offset++)
3343                 {
3344                         peek = tvb_get_guint8 (tvb, offset);
3345                         if (peek == '=')
3346                         {
3347                                 variableEnd = offset;
3348                                 valueStart = offset+1;
3349                         }
3350                         else if (peek == '&')
3351                         {
3352                                 if (variableEnd > 0)
3353                                 {
3354                                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
3355                                 }
3356                                 variableStart = offset+1;
3357                                 variableEnd = 0;
3358                                 valueStart = 0;
3359                                 valueEnd = 0;
3360                         }
3361                 }
3362
3363                 /* See if there's outstanding data */
3364                 if (variableEnd > 0)
3365                 {
3366                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
3367                 }
3368         }
3369         else if ((contentType == 0x22) || (contentType == 0x23) || (contentType == 0x23) || (contentType == 0x24) ||
3370                  (contentType == 0x25) || (contentType == 0x26) || (contentType == 0x33))
3371         {
3372                 add_multipart_data(ti, tvb);
3373         }
3374 }
3375
3376 static void
3377 add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
3378 {
3379         int variableLength = variableEnd-variableStart;
3380         int valueLength = 0;
3381         char *variableBuffer;
3382         char *valueBuffer;
3383
3384         variableBuffer = g_malloc (variableLength+1);
3385         strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength);
3386         variableBuffer[variableLength] = 0;
3387
3388         if (valueEnd < valueStart)
3389         {
3390                 valueBuffer = g_malloc (1);
3391                 valueBuffer[0] = 0;
3392                 valueEnd = valueStart;
3393         }
3394         else
3395         {
3396                 valueLength = valueEnd-valueStart;
3397                 valueBuffer = g_malloc (valueLength+1);
3398                 strncpy (valueBuffer, tvb_get_ptr (tvb, valueStart, valueLength), valueLength);
3399                 valueBuffer[valueLength] = 0;
3400         }
3401
3402         /* Check for variables with no value */
3403         if (valueStart >= tvb_reported_length (tvb))
3404         {
3405                 valueStart = tvb_reported_length (tvb);
3406                 valueEnd = valueStart;
3407         }
3408         valueLength = valueEnd-valueStart;
3409
3410         proto_tree_add_text (tree, tvb, variableStart, valueEnd-variableStart, "%s: %s", variableBuffer, valueBuffer);
3411
3412         g_free (variableBuffer);
3413         g_free (valueBuffer);
3414 }
3415
3416 void
3417 add_multipart_data (proto_tree *tree, tvbuff_t *tvb)
3418 {
3419         int              offset = 0;
3420         guint            nextOffset;
3421         guint            nEntries = 0;
3422         guint            count;
3423         guint            HeadersLen;
3424         guint            DataLen;
3425         guint            contentType = 0;
3426         const char      *contentTypeStr;
3427         tvbuff_t        *tmp_tvb;
3428         int              partnr = 1;
3429         int              part_start;
3430
3431         proto_item      *sub_tree = NULL,
3432                         *ti;
3433         proto_tree      *mpart_tree;
3434
3435         nEntries = tvb_get_guintvar (tvb, offset, &count);
3436         offset += count;
3437         if (nEntries)
3438         {
3439                 sub_tree = proto_tree_add_text(tree, tvb, offset - count, 0,
3440                                         "Multipart body");
3441                 proto_item_add_subtree(sub_tree, ett_mpartlist);
3442         }
3443         while (nEntries--)
3444         {
3445                 part_start = offset;
3446                 HeadersLen = tvb_get_guintvar (tvb, offset, &count);
3447                 offset += count;
3448                 DataLen = tvb_get_guintvar (tvb, offset, &count);
3449                 offset += count;
3450                 ti = proto_tree_add_uint(sub_tree, hf_wsp_mpart, tvb, part_start,
3451                                         HeadersLen + DataLen + (offset - part_start), partnr);
3452                 mpart_tree = proto_item_add_subtree(ti, ett_multiparts);
3453                 nextOffset = add_content_type (mpart_tree, tvb, offset, &contentType, &contentTypeStr);
3454                 HeadersLen -= (nextOffset - offset);
3455                 if (HeadersLen > 0)
3456                 {
3457                         tmp_tvb = tvb_new_subset (tvb, nextOffset, HeadersLen, HeadersLen);
3458                         add_headers (mpart_tree, tmp_tvb);
3459                 }
3460                 offset = nextOffset + HeadersLen;
3461                 proto_tree_add_item (mpart_tree, hf_wsp_multipart_data, tvb, offset, DataLen, bo_little_endian);
3462                 offset += DataLen;
3463                 partnr++;
3464         }
3465 }
3466
3467 static gint
3468 get_integer (tvbuff_t *tvb, guint offset, guint valueLength,
3469     value_type_t valueType, guint *value)
3470 {
3471         if (valueType == VALUE_IS_TEXT_STRING) {
3472                 /*
3473                  * Not valid.
3474                  */
3475                 return -1;
3476         }
3477
3478         if (valueType == VALUE_IN_LEN) {
3479                 /*
3480                  * Short-integer.
3481                  */
3482                 *value = valueLength;
3483                 return 0;
3484         }
3485
3486         /*
3487          * Long-integer.
3488          */
3489         switch (valueLength)
3490         {
3491                 case 1:
3492                         *value = tvb_get_guint8(tvb, offset);
3493                         break;
3494                 case 2:
3495                         *value = tvb_get_ntohs(tvb, offset);
3496                         break;
3497                 case 3:
3498                         *value = tvb_get_ntoh24(tvb, offset);
3499                         break;
3500                 case 4:
3501                         *value = tvb_get_ntohl(tvb, offset);
3502                         break;
3503                 default:
3504                         /* TODO: Need to read peek octets */
3505                         *value = 0;
3506                         fprintf (stderr, "dissect_wsp: get_integer size %u NYI\n", valueLength);
3507                         break;
3508         }
3509         return 0;
3510 }
3511
3512 /* Register the protocol with Ethereal */
3513 void
3514 proto_register_wsp(void)
3515 {                 
3516
3517 /* Setup list of header fields */
3518         static hf_register_info hf[] = {
3519                 { &hf_wsp_header_tid,
3520                         {       "Transmission ID",           
3521                                 "wsp.TID",
3522                                  FT_UINT8, BASE_HEX, NULL, 0x00,
3523                                 "Transmission ID", HFILL
3524                         }
3525                 },
3526                 { &hf_wsp_header_pdu_type,
3527                         {       "PDU Type",           
3528                                 "wsp.pdu_type",
3529                                  FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
3530                                 "PDU Type", HFILL
3531                         }
3532                 },
3533                 { &hf_wsp_version_major,
3534                         {       "Version (Major)",           
3535                                 "wsp.version.major",
3536                                  FT_UINT8, BASE_DEC, NULL, 0xF0,
3537                                 "Version (Major)", HFILL
3538                         }
3539                 },
3540                 { &hf_wsp_version_minor,
3541                         {       "Version (Minor)",           
3542                                 "wsp.version.minor",
3543                                  FT_UINT8, BASE_DEC, NULL, 0x0F,
3544                                 "Version (Minor)", HFILL
3545                         }
3546                 },
3547                 { &hf_wsp_capability_length,
3548                         {       "Capability Length",           
3549                                 "wsp.capability.length",
3550                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3551                                 "Capability Length", HFILL
3552                         }
3553                 },
3554                 { &hf_wsp_header_length,
3555                         {       "Headers Length",           
3556                                 "wsp.headers_length",
3557                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3558                                 "Headers Length", HFILL
3559                         }
3560                 },
3561                 { &hf_wsp_capabilities_section,
3562                         {       "Capabilities",           
3563                                 "wsp.capabilities",
3564                                  FT_NONE, BASE_DEC, NULL, 0x00,
3565                                 "Capabilities", HFILL
3566                         }
3567                 },
3568                 { &hf_wsp_headers_section,
3569                         {       "Headers",           
3570                                 "wsp.headers",
3571                                  FT_NONE, BASE_DEC, NULL, 0x00,
3572                                 "Headers", HFILL
3573                         }
3574                 },
3575                 { &hf_wsp_header,
3576                         {       "Header",           
3577                                 "wsp.headers.header",
3578                                  FT_NONE, BASE_DEC, NULL, 0x00,
3579                                 "Header", HFILL
3580                         }
3581                 },
3582                 { &hf_wsp_header_uri_len,
3583                         {       "URI Length",           
3584                                 "wsp.uri_length",
3585                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3586                                 "URI Length", HFILL
3587                         }
3588                 },
3589                 { &hf_wsp_header_uri,
3590                         {       "URI",           
3591                                 "wsp.uri",
3592                                  FT_STRING, BASE_NONE, NULL, 0x00,
3593                                 "URI", HFILL
3594                         }
3595                 },
3596                 { &hf_wsp_server_session_id,
3597                         {       "Server Session ID",           
3598                                 "wsp.server.session_id",
3599                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3600                                 "Server Session ID", HFILL
3601                         }
3602                 },
3603                 { &hf_wsp_header_status,
3604                         {       "Status",           
3605                                 "wsp.reply.status",
3606                                  FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
3607                                 "Status", HFILL
3608                         }
3609                 },
3610                 { &hf_wsp_content_type,
3611                         {       "Content Type",           
3612                                 "wsp.content_type.type",
3613                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
3614                                 "Content Type", HFILL
3615                         }
3616                 },
3617                 { &hf_wsp_content_type_str,
3618                         {       "Content Type",           
3619                                 "wsp.content_type.type.string",
3620                                  FT_STRING, BASE_NONE, NULL, 0x00,
3621                                 "Content Type", HFILL
3622                         }
3623                 },
3624                 { &hf_wsp_parameter_well_known_charset,
3625                         {       "Charset",           
3626                                 "wsp.content_type.parameter.charset",
3627                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
3628                                 "Charset", HFILL
3629                         }
3630                 },
3631                 { &hf_wsp_parameter_type,
3632                         {       "Type",           
3633                                 "wsp.content_type.parameter.type",
3634                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3635                                 "Type", HFILL
3636                         }
3637                 },
3638                 { &hf_wsp_parameter_name,
3639                         {       "Name",
3640                                 "wsp.content_type.parameter.name",
3641                                  FT_STRING, BASE_NONE, NULL, 0x00,
3642                                 "Name", HFILL
3643                         }
3644                 },
3645                 { &hf_wsp_parameter_filename,
3646                         {       "Filename",
3647                                 "wsp.content_type.parameter.filename",
3648                                  FT_STRING, BASE_NONE, NULL, 0x00,
3649                                 "Filename", HFILL
3650                         }
3651                 },
3652                 { &hf_wsp_parameter_start,
3653                         {       "Start",
3654                                 "wsp.content_type.parameter.start",
3655                                  FT_STRING, BASE_NONE, NULL, 0x00,
3656                                 "Start", HFILL
3657                         }
3658                 },
3659                 { &hf_wsp_parameter_start_info,
3660                         {       "Start-info",
3661                                 "wsp.content_type.parameter.start_info",
3662                                  FT_STRING, BASE_NONE, NULL, 0x00,
3663                                 "Start-info", HFILL
3664                         }
3665                 },
3666                 { &hf_wsp_parameter_comment,
3667                         {       "Comment",
3668                                 "wsp.content_type.parameter.comment",
3669                                  FT_STRING, BASE_NONE, NULL, 0x00,
3670                                 "Comment", HFILL
3671                         }
3672                 },
3673                 { &hf_wsp_parameter_domain,
3674                         {       "Domain",
3675                                 "wsp.content_type.parameter.domain",
3676                                  FT_STRING, BASE_NONE, NULL, 0x00,
3677                                 "Domain", HFILL
3678                         }
3679                 },
3680                 { &hf_wsp_parameter_path,
3681                         {       "Path",
3682                                 "wsp.content_type.parameter.path",
3683                                  FT_STRING, BASE_NONE, NULL, 0x00,
3684                                 "Path", HFILL
3685                         }
3686                 },
3687                 { &hf_wsp_parameter_upart_type,
3688                         {       "Type",
3689                                 "wsp.content_type.parameter.upart.type",
3690                                  FT_STRING, BASE_NONE, NULL, 0x00,
3691                                 "Multipart type", HFILL
3692                         }
3693                 },
3694                 { &hf_wsp_parameter_upart_type_value,
3695                         {       "Type",
3696                                 "wsp.content_type.parameter.upart.type.int",
3697                                  FT_UINT8, BASE_DEC, NULL, 0x00,
3698                                 "Multipart type (int value)", HFILL
3699                         }
3700                 },
3701                 { &hf_wsp_reply_data,
3702                         {       "Data",           
3703                                 "wsp.reply.data",
3704                                  FT_NONE, BASE_NONE, NULL, 0x00,
3705                                 "Data", HFILL
3706                         }
3707                 },
3708                 { &hf_wsp_header_shift_code,
3709                         {       "Shift code",           
3710                                 "wsp.header.shift",
3711                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3712                                  FT_UINT8, BASE_HEX, NULL, 0x00,
3713                                 "Shift code", HFILL
3714                         }
3715                 },
3716                 { &hf_wsp_header_accept,
3717                         {       "Accept",           
3718                                 "wsp.header.accept",
3719                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3720                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
3721                                 "Accept", HFILL
3722                         }
3723                 },
3724                 { &hf_wsp_header_accept_str,
3725                         {       "Accept",           
3726                                 "wsp.header.accept.string",
3727                                  FT_STRING, BASE_NONE, NULL, 0x00,
3728                                 "Accept", HFILL
3729                         }
3730                 },
3731                 { &hf_wsp_header_accept_application,
3732                         {       "Accept-Application",           
3733                                 "wsp.header.accept_application",
3734                                  FT_UINT32, BASE_HEX, NULL, 0x00,
3735                                 "Accept-Application", HFILL
3736                         }
3737                 },
3738                 { &hf_wsp_header_accept_application_str,
3739                         {       "Accept-Application",
3740                                 "wsp.header.accept_application.string",
3741                                  FT_STRING, BASE_NONE, NULL, 0x00,
3742                                 "Accept-Application", HFILL
3743                         }
3744                 },
3745                 { &hf_wsp_header_accept_charset,
3746                         {       "Accept-Charset",           
3747                                 "wsp.header.accept_charset",
3748                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
3749                                 "Accept-Charset", HFILL
3750                         }
3751                 },
3752                 { &hf_wsp_header_accept_charset_str,
3753                         {       "Accept-Charset",           
3754                                 "wsp.header.accept_charset.string",
3755                                  FT_STRING, BASE_NONE, NULL, 0x00,
3756                                 "Accept-Charset", HFILL
3757                         }
3758                 },
3759                 { &hf_wsp_header_accept_language,
3760                         {       "Accept-Language",           
3761                                 "wsp.header.accept_language",
3762                                  FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
3763                                 "Accept-Language", HFILL
3764                         }
3765                 },
3766                 { &hf_wsp_header_accept_language_str,
3767                         {       "Accept-Language",           
3768                                 "wsp.header.accept_language.string",
3769                                  FT_STRING, BASE_NONE, NULL, 0x00,
3770                                 "Accept-Language", HFILL
3771                         }
3772                 },
3773                 { &hf_wsp_header_accept_ranges,
3774                         {       "Accept-Ranges",           
3775                                 "wsp.header.accept_ranges",
3776                                  FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
3777                                 "Accept-Ranges", HFILL
3778                         }
3779                 },
3780                 { &hf_wsp_header_accept_ranges_str,
3781                         {       "Accept-Ranges",           
3782                                 "wsp.header.accept_ranges.string",
3783                                  FT_STRING, BASE_NONE, NULL, 0x00,
3784                                 "Accept-Ranges", HFILL
3785                         }
3786                 },
3787                 { &hf_wsp_header_age,
3788                         {       "Age",           
3789                                 "wsp.header.age",
3790                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3791                                 "Age", HFILL
3792                         }
3793                 },
3794                 { &hf_wsp_header_bearer_indication,
3795                         /*
3796                          * XXX - I'm assuming that the bearer indication is
3797                          * just a bearer type.
3798                          */
3799                         {       "Bearer-indication",           
3800                                 "wsp.header.bearer_indication",
3801                                  FT_UINT32, BASE_HEX, VALS(vals_bearer_types), 0x00,
3802                                 "Bearer-indication", HFILL
3803                         }
3804                 },
3805                 { &hf_wsp_header_cache_control,
3806                         {       "Cache-Control",           
3807                                 "wsp.header.cache_control",
3808                                  FT_UINT8, BASE_HEX, VALS ( vals_cache_control ), 0x00,
3809                                 "Cache-Control", HFILL
3810                         }
3811                 },
3812                 { &hf_wsp_header_cache_control_str,
3813                         {       "Cache-Control",           
3814                                 "wsp.header.cache_control.string",
3815                                  FT_STRING, BASE_NONE, NULL, 0x00,
3816                                 "Cache-Control", HFILL
3817                         }
3818                 },
3819                 { &hf_wsp_header_cache_control_field_name,
3820                         {       "Field Name",
3821                                 "wsp.header.cache_control.field_name",
3822                                  FT_UINT8, BASE_HEX, VALS ( vals_field_names ), 0x00,
3823                                 "Cache-Control field name", HFILL
3824                         }
3825                 },
3826                 { &hf_wsp_header_cache_control_field_name_str,
3827                         {       "Field Name",
3828                                 "wsp.header.cache_control.field_name.str",
3829                                  FT_STRING, BASE_NONE, NULL, 0x00,
3830                                 "Cache-Control field name", HFILL
3831                         }
3832                 },
3833                 { &hf_wsp_header_connection,
3834                         {       "Connection",           
3835                                 "wsp.header.connection",
3836                                  FT_UINT8, BASE_HEX, VALS ( vals_connection ), 0x00,
3837                                 "Connection", HFILL
3838                         }
3839                 },
3840                 { &hf_wsp_header_connection_str,
3841                         {       "Connection",           
3842                                 "wsp.header.connection_str",
3843                                  FT_STRING, BASE_NONE, NULL, 0x00,
3844                                 "Connection", HFILL
3845                         }
3846                 },
3847                 { &hf_wsp_header_content_length,
3848                         {       "Content-Length",           
3849                                 "wsp.header.content_length",
3850                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3851                                 "Content-Length", HFILL
3852                         }
3853                 },
3854                 { &hf_wsp_header_date,
3855                         {       "Date",           
3856                                 "wsp.header.date",
3857                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
3858                                 "Date", HFILL
3859                         }
3860                 },
3861                 { &hf_wsp_header_etag,
3862                         {       "Etag",           
3863                                 "wsp.header.etag",
3864                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3865                                  FT_STRING, BASE_NONE, NULL, 0x00,
3866                                 "Etag", HFILL
3867                         }
3868                 },
3869                 { &hf_wsp_header_expires,
3870                         {       "Expires",           
3871                                 "wsp.header.expires",
3872                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
3873                                 "Expires", HFILL
3874                         }
3875                 },
3876                 { &hf_wsp_header_last_modified,
3877                         {       "Last-Modified",           
3878                                 "wsp.header.last_modified",
3879                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
3880                                 "Last-Modified", HFILL
3881                         }
3882                 },
3883                 { &hf_wsp_header_location,
3884                         {       "Location",           
3885                                 "wsp.header.location",
3886                                  FT_STRING, BASE_NONE, NULL, 0x00,
3887                                 "Location", HFILL
3888                         }
3889                 },
3890                 { &hf_wsp_header_if_modified_since,
3891                         {       "If-Modified-Since",           
3892                                 "wsp.header.if_modified_since",
3893                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
3894                                 "If-Modified-Since", HFILL
3895                         }
3896                 },
3897                 { &hf_wsp_header_pragma,
3898                         {       "Pragma",           
3899                                 "wsp.header.pragma",
3900                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3901                                  FT_STRING, BASE_NONE, NULL, 0x00,
3902                                 "pragma", HFILL
3903                         }
3904                 },
3905                 { &hf_wsp_header_profile,
3906                         {       "Profile",           
3907                                 "wsp.header.profile",
3908                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3909                                  FT_STRING, BASE_NONE, NULL, 0x00,
3910                                 "Profile", HFILL
3911                         }
3912                 },
3913                 { &hf_wsp_header_server,
3914                         {       "Server",           
3915                                 "wsp.header.server",
3916                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3917                                  FT_STRING, BASE_NONE, NULL, 0x00,
3918                                 "Server", HFILL
3919                         }
3920                 },
3921                 { &hf_wsp_header_transfer_encoding,
3922                         {       "Transfer Encoding",           
3923                                 "wsp.header.transfer_enc",
3924                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3925                                  FT_UINT8, BASE_HEX, VALS ( vals_transfer_encoding ), 0x00,
3926                                 "Transfer Encoding", HFILL
3927                         }
3928                 },
3929                 { &hf_wsp_header_transfer_encoding_str,
3930                         {       "Transfer Encoding",           
3931                                 "wsp.header.transfer_enc_str",
3932                                  FT_STRING, BASE_NONE, NULL, 0x00,
3933                                 "Transfer Encoding", HFILL
3934                         }
3935                 },
3936                 { &hf_wsp_header_user_agent,
3937                         {       "User-Agent",           
3938                                 "wsp.header.user_agent",
3939                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3940                                  FT_STRING, BASE_NONE, NULL, 0x00,
3941                                 "User-Agent", HFILL
3942                         }
3943                 },
3944                 { &hf_wsp_header_via,
3945                         {       "Via",           
3946                                 "wsp.header.via",
3947                                  FT_STRING, BASE_NONE, NULL, 0x00,
3948                                 "Via", HFILL
3949                         }
3950                 },
3951                 { &hf_wsp_header_wap_application_id,
3952                         {       "X-Wap-Application-Id",           
3953                                 "wsp.header.wap_application_id",
3954                                  FT_UINT8, BASE_HEX, NULL, 0x00,
3955                                 "WAP application id", HFILL
3956                         }
3957                 },
3958                 { &hf_wsp_header_wap_application_id_str,
3959                         {       "X-Wap-Application-Id",           
3960                                 "wsp.header.wap_application_id.string",
3961                                  FT_STRING, BASE_NONE, NULL, 0x00,
3962                                 "WAP application id", HFILL
3963                         }
3964                 },
3965                 { &hf_wsp_header_warning,
3966                         {       "Warning",
3967                                 "wsp.header.warning",
3968                                  FT_NONE, BASE_NONE, NULL, 0x00,
3969                                 "Warning", HFILL
3970                         }
3971                 },
3972                 { &hf_wsp_header_warning_code,
3973                         {       "Warning Code",
3974                                 "wsp.header.warning.code",
3975                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3976                                 "Warning Code", HFILL
3977                         }
3978                 },
3979                 { &hf_wsp_header_warning_agent,
3980                         {       "Warning Agent",
3981                                 "wsp.header.warning.agent",
3982                                  FT_STRING, BASE_NONE, NULL, 0x00,
3983                                 "Warning Agent", HFILL
3984                         }
3985                 },
3986                 { &hf_wsp_header_warning_text,
3987                         {       "Warning Text",
3988                                 "wsp.header.warning.text",
3989                                  FT_STRING, BASE_NONE, NULL, 0x00,
3990                                 "Warning Text", HFILL
3991                         }
3992                 },
3993                 { &hf_wsp_header_application_header,
3994                         {       "Application Header",           
3995                                 "wsp.header.application_header",
3996                                  FT_STRING, BASE_NONE, NULL, 0x00,
3997                                 "Application Header", HFILL
3998                         }
3999                 },
4000                 { &hf_wsp_header_application_value,
4001                         {       "Application Header Value",           
4002                                 "wsp.header.application_header.value",
4003                                  FT_STRING, BASE_NONE, NULL, 0x00,
4004                                 "Application Header Value", HFILL
4005                         }
4006                 },
4007                 { &hf_wsp_header_content_ID,
4008                         {       "Content-ID",           
4009                                 "wsp.header.content-id",
4010                                  FT_STRING, BASE_NONE, NULL, 0x00,
4011                                 "Content-ID", HFILL
4012                         }
4013                 },
4014                 { &hf_wsp_header_x_wap_tod,
4015                         {       "X-WAP.TOD",           
4016                                 "wsp.header.x_wap_tod",
4017                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
4018                                 "X-WAP.TOD", HFILL
4019                         }
4020                 },
4021                 { &hf_wsp_capabilities_client_SDU,
4022                         {       "Client SDU",
4023                                 "wsp.capabilities.client_SDU",
4024                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4025                                 "Client SDU", HFILL
4026                         }
4027                 },
4028                 { &hf_wsp_capabilities_server_SDU,
4029                         {       "Server SDU",
4030                                 "wsp.capabilities.server_SDU",
4031                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4032                                 "Server SDU", HFILL
4033                         }
4034                 },
4035                 { &hf_wsp_capabilities_protocol_opt,
4036                         {       "Protocol Options",
4037                                 "wsp.capabilities.protocol_opt",
4038                                  FT_STRING, BASE_HEX, NULL, 0x00,
4039                                 "Protocol Options", HFILL
4040                         }
4041                 },
4042                 { &hf_wsp_capabilities_method_MOR,
4043                         {       "Method MOR",
4044                                 "wsp.capabilities.method_mor",
4045                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4046                                 "Method MOR", HFILL
4047                         }
4048                 },
4049                 { &hf_wsp_capabilities_push_MOR,
4050                         {       "Push MOR",
4051                                 "wsp.capabilities.push_mor",
4052                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4053                                 "Push MOR", HFILL
4054                         }
4055                 },
4056                 { &hf_wsp_capabilities_extended_methods,
4057                         {       "Extended Methods",
4058                                 "wsp.capabilities.extend_methods",
4059                                  FT_STRING, BASE_HEX, NULL, 0x00,
4060                                 "Extended Methods", HFILL
4061                         }
4062                 },
4063                 { &hf_wsp_capabilities_header_code_pages,
4064                         {       "Header Code Pages",
4065                                 "wsp.capabilities.code_pages",
4066                                  FT_STRING, BASE_HEX, NULL, 0x00,
4067                                 "Header Code Pages", HFILL
4068                         }
4069                 },
4070                 { &hf_wsp_capabilities_aliases,
4071                         {       "Aliases",
4072                                 "wsp.capabilities.aliases",
4073                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4074                                 "Aliases", HFILL
4075                         }
4076                 },
4077                 { &hf_wsp_post_data,
4078                         {       "Post Data",           
4079                                 "wsp.post.data",
4080                                  FT_NONE, BASE_NONE, NULL, 0x00,
4081                                 "Post Data", HFILL
4082                         }
4083                 },
4084                 { &hf_wsp_push_data,
4085                         {       "Push Data",           
4086                                 "wsp.push.data",
4087                                  FT_NONE, BASE_NONE, NULL, 0x00,
4088                                 "Push Data", HFILL
4089                         }
4090                 },
4091                 { &hf_wsp_multipart_data,
4092                         {       "Data in this part",           
4093                                 "wsp.multipart.data",
4094                                  FT_NONE, BASE_NONE, NULL, 0x00,
4095                                 "The data of 1 MIME-multipart part.", HFILL
4096                         }
4097                 },
4098                 { &hf_wsp_mpart,
4099                         {       "Part",           
4100                                 "wsp.multipart",
4101                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4102                                 "MIME part of multipart data.", HFILL
4103                         }
4104                 },
4105                 { &hf_wsp_redirect_flags,
4106                         {       "Flags",
4107                                 "wsp.redirect_flags",
4108                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4109                                 "Redirect Flags", HFILL
4110                         }
4111                 },
4112                 { &hf_wsp_redirect_permanent,
4113                         {       "Permanent Redirect",
4114                                 "wsp.redirect_flags.permanent",
4115                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), PERMANENT_REDIRECT,
4116                                 "Permanent Redirect", HFILL
4117                         }
4118                 },
4119                 { &hf_wsp_redirect_reuse_security_session,
4120                         {       "Reuse Security Session",
4121                                 "wsp.redirect_flags.reuse_security_session",
4122                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), REUSE_SECURITY_SESSION,
4123                                 "Permanent Redirect", HFILL
4124                         }
4125                 },
4126                 { &hf_wsp_redirect_afl,
4127                         {       "Flags/Length",
4128                                 "wsp.redirect_afl",
4129                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4130                                 "Redirect Address Flags/Length", HFILL
4131                         }
4132                 },
4133                 { &hf_wsp_redirect_afl_bearer_type_included,
4134                         {       "Bearer Type Included",
4135                                 "wsp.redirect_afl.bearer_type_included",
4136                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), BEARER_TYPE_INCLUDED,
4137                                 "Redirect Address bearer type included", HFILL
4138                         }
4139                 },
4140                 { &hf_wsp_redirect_afl_port_number_included,
4141                         {       "Port Number Included",
4142                                 "wsp.redirect_afl.port_number_included",
4143                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), PORT_NUMBER_INCLUDED,
4144                                 "Redirect Address port number included", HFILL
4145                         }
4146                 },
4147                 { &hf_wsp_redirect_afl_address_len,
4148                         {       "Address Len",
4149                                 "wsp.redirect_afl.address_len",
4150                                  FT_UINT8, BASE_DEC, NULL, ADDRESS_LEN,
4151                                 "Redirect Address Length", HFILL
4152                         }
4153                 },
4154                 { &hf_wsp_redirect_bearer_type,
4155                         {       "Bearer Type",
4156                                 "wsp.redirect_bearer_type",
4157                                  FT_UINT8, BASE_HEX, VALS(vals_bearer_types), 0x0,
4158                                 "Redirect Bearer Type", HFILL
4159                         }
4160                 },
4161                 { &hf_wsp_redirect_port_num,
4162                         {       "Port Number",
4163                                 "wsp.redirect_port_num",
4164                                  FT_UINT16, BASE_DEC, NULL, 0x0,
4165                                 "Redirect Port Number", HFILL
4166                         }
4167                 },
4168                 { &hf_wsp_redirect_ipv4_addr,
4169                         {       "IP Address",
4170                                 "wsp.redirect_ipv4_addr",
4171                                  FT_IPv4, BASE_NONE, NULL, 0x0,
4172                                 "Redirect Address (IP)", HFILL
4173                         }
4174                 },
4175                 { &hf_wsp_redirect_ipv6_addr,
4176                         {       "IPv6 Address",
4177                                 "wsp.redirect_ipv6_addr",
4178                                  FT_IPv6, BASE_NONE, NULL, 0x0,
4179                                 "Redirect Address (IPv6)", HFILL
4180                         }
4181                 },
4182                 { &hf_wsp_redirect_addr,
4183                         {       "Address",
4184                                 "wsp.redirect_addr",
4185                                  FT_BYTES, BASE_NONE, NULL, 0x0,
4186                                 "Redirect Address", HFILL
4187                         }
4188                 },
4189         };
4190         
4191 /* Setup protocol subtree array */
4192         static gint *ett[] = {
4193                 &ett_wsp,
4194                 &ett_content_type_parameters,
4195                 &ett_header,
4196                 &ett_headers,
4197                 &ett_header_warning,
4198                 &ett_header_cache_control_parameters,
4199                 &ett_header_cache_control_field_names,
4200                 &ett_capabilities,
4201                 &ett_content_type,
4202                 &ett_redirect_flags,
4203                 &ett_redirect_afl,
4204                 &ett_multiparts,
4205                 &ett_mpartlist
4206         };
4207
4208 /* Register the protocol name and description */
4209         proto_wsp = proto_register_protocol(
4210                 "Wireless Session Protocol",    /* protocol name for use by ethereal */ 
4211                 "WSP",                          /* short version of name */
4212                 "wap-wsp"                       /* Abbreviated protocol name, should Match IANA 
4213                                                     < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
4214                                                   */
4215         );
4216
4217 /* Required function calls to register the header fields and subtrees used  */
4218         proto_register_field_array(proto_wsp, hf, array_length(hf));
4219         proto_register_subtree_array(ett, array_length(ett));
4220
4221         register_dissector("wsp-co", dissect_wsp_fromwap_co, proto_wsp);
4222         register_dissector("wsp-cl", dissect_wsp_fromwap_cl, proto_wsp);
4223         wsp_dissector_table = register_dissector_table("wsp.content_type.type",
4224             "WSP content type", FT_UINT8, BASE_HEX);
4225         register_heur_dissector_list("wsp", &heur_subdissector_list);
4226
4227         wsp_fromudp_handle = create_dissector_handle(dissect_wsp_fromudp,
4228             proto_wsp);
4229 };
4230
4231 void
4232 proto_reg_handoff_wsp(void)
4233 {
4234         /*
4235          * Get a handle for the WMLC dissector.
4236          */
4237         wmlc_handle = find_dissector("wmlc");   /* Coming soon :) */
4238
4239         /*
4240          * And get a handle for the WTP-over-UDP dissector.
4241          */
4242         wtp_fromudp_handle = find_dissector("wtp-udp");
4243
4244         /* Only connection-less WSP has no previous handler */
4245         dissector_add("udp.port", UDP_PORT_WSP, wsp_fromudp_handle);
4246         dissector_add("udp.port", UDP_PORT_WSP_PUSH, wsp_fromudp_handle);
4247
4248         /* This dissector is also called from the WTP and WTLS dissectors */
4249 }