Add in the SliMP3 data protocol dissector.
[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.50 2001/12/10 00:25:41 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 *, packet_info *, 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         int offset = 0;
997
998         guint8 pdut;
999         guint count = 0;
1000         guint value = 0;
1001         guint uriLength = 0;
1002         guint uriStart = 0;
1003         guint capabilityLength = 0;
1004         guint capabilityStart = 0;
1005         guint headersLength = 0;
1006         guint headerLength = 0;
1007         guint headerStart = 0;
1008         guint nextOffset = 0;
1009         guint contentTypeStart = 0;
1010         guint contentType = 0;
1011         const char *contentTypeStr;
1012         tvbuff_t *tmp_tvb;
1013
1014 /* Set up structures we will need to add the protocol subtree and manage it */
1015         proto_item *ti;
1016         proto_tree *wsp_tree = NULL;
1017 /*      proto_tree *wsp_header_fixed; */
1018         
1019 /* This field shows up as the "Info" column in the display; you should make
1020    it, if possible, summarize what's in the packet, so that a user looking
1021    at the list of packets can tell what type of packet it is. */
1022     
1023         /* Connection-less mode has a TID first */
1024         if (is_connectionless)
1025         {
1026                 offset++;
1027         };
1028
1029         /* Find the PDU type */
1030         pdut = tvb_get_guint8 (tvb, offset);
1031
1032         /* Develop the string to put in the Info column */
1033         if (check_col(pinfo->cinfo, COL_INFO))
1034         {
1035                 col_append_fstr(pinfo->cinfo, COL_INFO, "WSP %s",
1036                         val_to_str (pdut, vals_pdu_type, "Unknown PDU type (0x%02x)"));
1037         };
1038
1039 /* In the interest of speed, if "tree" is NULL, don't do any work not
1040    necessary to generate protocol tree items. */
1041         if (tree) {
1042                 ti = proto_tree_add_item(tree, proto_wsp, tvb, 0,
1043                     tvb_length(tvb), bo_little_endian);
1044                 wsp_tree = proto_item_add_subtree(ti, ett_wsp);
1045
1046 /* Code to process the packet goes here */
1047 /*
1048                 wsp_header_fixed = proto_item_add_subtree(ti, ett_header );
1049 */
1050
1051                 /* Add common items: only TID and PDU Type */
1052
1053                 /* If this is connectionless, then the TID Field is always first */
1054                 if (is_connectionless)
1055                 {
1056                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_tid,tvb,
1057                                 0,1,bo_little_endian);
1058                 }
1059
1060                 ti = proto_tree_add_item(
1061                                 wsp_tree,               /* tree */
1062                                 hf_wsp_header_pdu_type, /* id */
1063                                 tvb, 
1064                                 offset,                 /* start of high light */
1065                                 1,                      /* length of high light */
1066                                 bo_little_endian        /* value */
1067                      );
1068         }
1069         offset++;
1070
1071         switch (pdut)
1072         {
1073                 case CONNECT:
1074                 case CONNECTREPLY:
1075                 case RESUME:
1076                         if (tree) {
1077                                 if (pdut == CONNECT)
1078                                 {
1079                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
1080                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
1081                                         offset++;
1082                                 } else {
1083                                         count = 0;      /* Initialise count */
1084                                         value = tvb_get_guintvar (tvb, offset, &count);
1085                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
1086                                         offset += count;
1087                                 }
1088                                 capabilityStart = offset;
1089                                 count = 0;      /* Initialise count */
1090                                 capabilityLength = tvb_get_guintvar (tvb, offset, &count);
1091                                 offset += count;
1092                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
1093
1094                                 if (pdut != RESUME)
1095                                 {
1096                                         count = 0;      /* Initialise count */
1097                                         headerLength = tvb_get_guintvar (tvb, offset, &count);
1098                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset,count,headerLength);
1099                                         offset += count;
1100                                         capabilityStart = offset;
1101                                         headerStart = capabilityStart + capabilityLength;
1102                                 } else {
1103                                                 /* Resume computes the headerlength by remaining bytes */
1104                                         capabilityStart = offset;
1105                                         headerStart = capabilityStart + capabilityLength;
1106                                         headerLength = tvb_reported_length_remaining (tvb, headerStart);
1107                                 }
1108                                 if (capabilityLength > 0)
1109                                 {
1110                                         tmp_tvb = tvb_new_subset (tvb, offset, capabilityLength, capabilityLength);
1111                                         add_capabilities (wsp_tree, tmp_tvb, pdut);
1112                                         offset += capabilityLength;
1113                                 }
1114
1115                                 if (headerLength > 0)
1116                                 {
1117                                         tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
1118                                         add_headers (wsp_tree, tmp_tvb);
1119                                 }
1120                         }
1121
1122                         break;
1123
1124                 case REDIRECT:
1125                         dissect_redirect(tvb, offset, pinfo, wsp_tree,
1126                           dissector_handle);
1127                         break;
1128
1129                 case DISCONNECT:
1130                 case SUSPEND:
1131                         if (tree) {
1132                                 count = 0;      /* Initialise count */
1133                                 value = tvb_get_guintvar (tvb, offset, &count);
1134                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
1135                         }
1136                         break;
1137
1138                 case GET:
1139                         count = 0;      /* Initialise count */
1140                                 /* Length of URI and size of URILen field */
1141                         value = tvb_get_guintvar (tvb, offset, &count);
1142                         nextOffset = offset + count;
1143                         add_uri (wsp_tree, pinfo, tvb, offset, nextOffset);
1144                         if (tree) {
1145                                 offset += (value+count); /* VERIFY */
1146                                 tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
1147                                 add_headers (wsp_tree, tmp_tvb);
1148                         }
1149                         break;
1150
1151                 case POST:
1152                         uriStart = offset;
1153                         count = 0;      /* Initialise count */
1154                         uriLength = tvb_get_guintvar (tvb, offset, &count);
1155                         headerStart = uriStart+count;
1156                         count = 0;      /* Initialise count */
1157                         headersLength = tvb_get_guintvar (tvb, headerStart, &count);
1158                         offset = headerStart + count;
1159
1160                         add_uri (wsp_tree, pinfo, tvb, uriStart, offset);
1161                         if (tree) {
1162                                 offset += uriLength;
1163
1164                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headersLength);
1165
1166                                 if (headersLength == 0)
1167                                         break;
1168
1169                                 contentTypeStart = offset;
1170                                 nextOffset = add_content_type (wsp_tree,
1171                                     tvb, offset, &contentType,
1172                                     &contentTypeStr);
1173
1174                                 /* Add headers subtree that will hold the headers fields */
1175                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1176                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1177                                 if (headerLength > 0)
1178                                 {
1179                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1180                                         add_headers (wsp_tree, tmp_tvb);
1181                                 }
1182
1183                                 /* TODO: Post DATA */
1184                                 /* Runs from start of headers+headerLength to end of frame */
1185                                 offset = nextOffset+headerLength;
1186                                 tmp_tvb = tvb_new_subset (tvb, offset, tvb_reported_length (tvb)-offset, tvb_reported_length (tvb)-offset);
1187                                 add_post_data (wsp_tree, tmp_tvb,
1188                                     contentType, contentTypeStr);
1189                         }
1190                         if (tvb_reported_length_remaining(tvb, headerStart + count + uriLength + headersLength) > 0)
1191                         {
1192                                 tmp_tvb = tvb_new_subset (tvb, headerStart + count + uriLength + headersLength, -1, -1);
1193                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1194                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1195                         }
1196                         break;
1197
1198                 case REPLY:
1199                         count = 0;      /* Initialise count */
1200                         headersLength = tvb_get_guintvar (tvb, offset+1, &count);
1201                         headerStart = offset + count + 1;
1202                         if (tree) {
1203                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
1204                                 nextOffset = offset + 1 + count;
1205                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,headersLength);
1206
1207                                 if (headersLength == 0)
1208                                         break;
1209
1210                                 contentTypeStart = nextOffset;
1211                                 nextOffset = add_content_type (wsp_tree,
1212                                     tvb, nextOffset, &contentType,
1213                                     &contentTypeStr);
1214
1215                                 /* Add headers subtree that will hold the headers fields */
1216                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1217                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1218                                 if (headerLength > 0)
1219                                 {
1220                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1221                                         add_headers (wsp_tree, tmp_tvb);
1222                                 }
1223                                 offset += count+headersLength+1;
1224
1225                                 /* TODO: Data - decode WMLC */
1226                                 /* Runs from offset+1+count+headerLength+1 to end of frame */
1227                                 if (tvb_reported_length_remaining (tvb, offset) > 0)
1228                                 {
1229                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,tvb_length_remaining(tvb, offset),bo_little_endian);
1230                                 }
1231                         }
1232                         if (tvb_reported_length_remaining(tvb, headerStart + headersLength) > 0)
1233                         {
1234                                 tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength, -1, -1);
1235                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1236                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1237                         }
1238                         break;
1239
1240                 case PUSH:
1241                 case CONFIRMEDPUSH:
1242                         count = 0;      /* Initialise count */
1243                         headersLength = tvb_get_guintvar (tvb, offset, &count);
1244                         headerStart = offset + count;
1245
1246                         if (tree) {
1247                                 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset,count,headersLength);
1248
1249                                 if (headersLength == 0)
1250                                         break;
1251
1252                                 offset += count;
1253                                 contentTypeStart = offset;
1254                                 nextOffset = add_content_type (wsp_tree,
1255                                     tvb, offset, &contentType,
1256                                     &contentTypeStr);
1257
1258                                 /* Add headers subtree that will hold the headers fields */
1259                                 /* Runs from nextOffset for headersLength-(length of content-type field)*/
1260                                 headerLength = headersLength-(nextOffset-contentTypeStart);
1261                                 if (headerLength > 0)
1262                                 {
1263                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
1264                                         add_headers (wsp_tree, tmp_tvb);
1265                                 }
1266                                 offset += headersLength;
1267
1268                                 /* Push DATA */
1269                                 if (tvb_reported_length_remaining (tvb, offset) > 0)
1270                                 {
1271                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_push_data,tvb,offset,tvb_length_remaining(tvb, offset),bo_little_endian);
1272                                 }
1273                         }
1274                         if (tvb_reported_length_remaining(tvb, headerStart + headersLength) > 0)
1275                         {
1276                                 tmp_tvb = tvb_new_subset (tvb, headerStart + headersLength, -1, -1);
1277                                 if (!dissector_try_port(wsp_dissector_table, contentType, tmp_tvb, pinfo, tree))
1278                                         dissector_try_heuristic(heur_subdissector_list, tmp_tvb, pinfo, tree);
1279                         }
1280                         break;
1281
1282         }
1283 }
1284
1285 /*
1286  * Called directly from UDP.
1287  * Put "WSP" into the "Protocol" column.
1288  */
1289 static void
1290 dissect_wsp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1291 {
1292         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1293                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WSP" );
1294         if (check_col(pinfo->cinfo, COL_INFO))
1295                 col_clear(pinfo->cinfo, COL_INFO);
1296
1297         dissect_wsp_common(tvb, pinfo, tree, wsp_fromudp_handle, TRUE);
1298 }
1299
1300 /*
1301  * Called from a higher-level WAP dissector, in connection-oriented mode.
1302  * Leave the "Protocol" column alone - the dissector calling us should
1303  * have set it.
1304  */
1305 static void
1306 dissect_wsp_fromwap_co(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1307 {
1308         /*
1309          * XXX - what about WTLS->WTP->WSP?
1310          */
1311         dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, FALSE);
1312 }
1313
1314 /*
1315  * Called from a higher-level WAP dissector, in connectionless mode.
1316  * Leave the "Protocol" column alone - the dissector calling us should
1317  * have set it.
1318  */
1319 static void
1320 dissect_wsp_fromwap_cl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1321 {
1322         /*
1323          * XXX - what about WTLS->WSP?
1324          */
1325         if (check_col(pinfo->cinfo, COL_INFO))
1326         {
1327                 col_clear(pinfo->cinfo, COL_INFO);
1328         }
1329         dissect_wsp_common(tvb, pinfo, tree, wtp_fromudp_handle, TRUE);
1330 }
1331
1332 static void
1333 add_uri (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
1334 {
1335         proto_item *ti;
1336         char *newBuffer;
1337
1338         guint count = 0;
1339         guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
1340
1341         if (tree)
1342                 ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
1343
1344         newBuffer = g_malloc (uriLen+2);
1345         newBuffer[0] = ' ';  /* This is for COL_INFO */
1346         strncpy (newBuffer+1, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
1347         newBuffer[uriLen+1] = 0;
1348         if (tree)
1349                 ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer+1);
1350         if (check_col(pinfo->cinfo, COL_INFO)) {
1351                 col_append_str(pinfo->cinfo, COL_INFO, newBuffer);
1352         };
1353         g_free (newBuffer);
1354 }
1355
1356 static void
1357 add_headers (proto_tree *tree, tvbuff_t *tvb)
1358 {
1359         proto_item *ti;
1360         proto_tree *wsp_headers;
1361         guint offset = 0;
1362         guint headersLen = tvb_reported_length (tvb);
1363         guint headerStart = 0;
1364         guint peek = 0;
1365         guint pageCode = 1;
1366
1367 #ifdef DEBUG
1368         fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, headersLen);
1369 #endif
1370
1371         /* End of buffer */
1372         if (headersLen <= 0)
1373         {
1374                 return;
1375         }
1376
1377 #ifdef DEBUG
1378         fprintf (stderr, "dissect_wsp: Headers to process\n");
1379 #endif
1380
1381         ti = proto_tree_add_item (tree, hf_wsp_headers_section,tvb,offset,headersLen,bo_little_endian);
1382         wsp_headers = proto_item_add_subtree( ti, ett_headers );
1383
1384         /* Parse Headers */
1385
1386         while (offset < headersLen)
1387         {
1388                 /* Loop round each header */
1389                 headerStart = offset;
1390                 peek = tvb_get_guint8 (tvb, headerStart);
1391
1392                 if (peek < 32)          /* Short-cut shift delimiter */
1393                 {
1394                         pageCode = peek;
1395                         proto_tree_add_uint (wsp_headers,
1396                             hf_wsp_header_shift_code, tvb, offset, 1,
1397                             pageCode);
1398                         offset += 1;
1399                         continue;
1400                 }
1401                 else if (peek == 0x7F)  /* Shift delimiter */
1402                 {
1403                         pageCode = tvb_get_guint8(tvb, offset+1);
1404                         proto_tree_add_uint (wsp_headers,
1405                             hf_wsp_header_shift_code, tvb, offset, 2,
1406                             pageCode);
1407                         offset += 2;
1408                         continue;
1409                 }
1410                 else if (peek < 127)
1411                 {
1412 #ifdef DEBUG
1413                         fprintf (stderr, "dissect_wsp: header: application-header start %d (0x%02X)\n", peek, peek);
1414 #endif
1415                         /*
1416                          * Token-text, followed by Application-specific-value.
1417                          */
1418                         offset = add_application_header (wsp_headers, tvb,
1419                             headerStart);
1420                 }
1421                 else if (peek & 0x80)
1422                 {
1423 #ifdef DEBUG
1424                         fprintf (stderr, "dissect_wsp: header: well-known %d (0x%02X)\n", peek, peek);
1425 #endif
1426                         /*
1427                          * Well-known-header; the lower 7 bits of "peek"
1428                          * are the header code.
1429                          */
1430                         if (pageCode == 1)
1431                         {
1432                                 offset = add_well_known_header (wsp_headers,
1433                                     tvb, headerStart, peek & 0x7F);
1434                         }
1435                         else 
1436                         {
1437                                 offset = add_unknown_header (wsp_headers,
1438                                     tvb, headerStart, peek & 0x7F);
1439                         }
1440                 }
1441         }
1442 }
1443
1444 static int
1445 add_well_known_header (proto_tree *tree, tvbuff_t *tvb, int offset,
1446     guint8 headerType)
1447 {
1448         int headerStart;
1449         value_type_t valueType;
1450         int headerLen;
1451         guint valueLen;
1452         int valueStart;
1453         tvbuff_t *header_buff;
1454         tvbuff_t *value_buff;
1455
1456 #ifdef DEBUG
1457         fprintf (stderr, "dissect_wsp: Got header 0x%02x\n", headerType);
1458 #endif
1459         headerStart = offset;
1460
1461         /*
1462          * Skip the Short-Integer header type.
1463          */
1464         offset++;
1465
1466         /*
1467          * Get the value type and length (or, if the type is VALUE_IN_LEN,
1468          * meaning the value is a Short-integer, get the value type
1469          * and the value itself).
1470          */ 
1471         valueType = get_value_type_len (tvb, offset, &valueLen,
1472             &valueStart, &offset);
1473         headerLen = offset - headerStart;
1474
1475         /*
1476          * Get a tvbuff for the entire header.
1477          * XXX - cut the actual length short so that it doesn't run
1478          * past the actual length of tvb.
1479          */
1480         header_buff = tvb_new_subset (tvb, headerStart, headerLen,
1481             headerLen);
1482
1483         /*
1484          * If the value wasn't in the length, get a tvbuff for the value.
1485          * XXX - can valueLen be 0?
1486          * XXX - cut the actual length short so that it doesn't run
1487          * past the actual length of tvb.
1488          */
1489         if (valueType != VALUE_IN_LEN) {
1490                 value_buff = tvb_new_subset (tvb, valueStart, valueLen,
1491                     valueLen);
1492         } else {
1493                 /*
1494                  * XXX - when the last dissector is tvbuffified,
1495                  * so that NULL is no longer a valid tvb pointer
1496                  * value in "proto_tree_add" calls, just
1497                  * set "value_buff" to NULL.
1498                  *
1499                  * XXX - can we already do that?  I.e., will that
1500                  * cause us always to crash if we mistakenly try
1501                  * to fetch the value of a VALUE_IN_LEN item?
1502                  */
1503                 value_buff = tvb_new_subset (tvb, headerStart, 0, 0);
1504         }
1505
1506         switch (headerType) {
1507
1508         case FN_ACCEPT:                 /* Accept */
1509                 add_accept_header (tree, header_buff, headerLen,
1510                     value_buff, valueType, valueLen);
1511                 break;
1512
1513         case FN_ACCEPT_CHARSET_DEP:     /* Accept-Charset */
1514                 /*
1515                  * XXX - should both encoding versions 1.1 and
1516                  * 1.3 be handled this way?
1517                  */
1518                 add_accept_xxx_header (tree, header_buff, headerLen,
1519                     value_buff, valueType, valueLen,
1520                     hf_wsp_header_accept_charset,
1521                     hf_wsp_header_accept_charset_str,
1522                     vals_character_sets, "Unknown charset (%u)");
1523                 break;
1524
1525         case FN_ACCEPT_LANGUAGE:        /* Accept-Language */
1526                 add_accept_xxx_header (tree, header_buff, headerLen,
1527                     value_buff, valueType, valueLen,
1528                     hf_wsp_header_accept_language,
1529                     hf_wsp_header_accept_language_str,
1530                     vals_languages, "Unknown language (%u)");
1531                 break;
1532
1533         case FN_ACCEPT_RANGES:          /* Accept-Ranges */
1534                 add_accept_ranges_header (tree, header_buff, headerLen,
1535                     value_buff, valueType, valueLen);
1536                 break;
1537
1538         case FN_AGE:                    /* Age */
1539                 add_integer_value_header (tree, header_buff, headerLen,
1540                     value_buff, valueType, valueLen, hf_wsp_header_age,
1541                     headerType);
1542                 break;
1543
1544         case FN_CACHE_CONTROL_DEP:      /* Cache-Control */
1545         case FN_CACHE_CONTROL:
1546         case FN_CACHE_CONTROL14:
1547                 /*
1548                  * XXX - is the only difference in the three different
1549                  * versions (1.1, 1.3, 1.4) really only S_MAXAGE?
1550                  */
1551                 add_cache_control_header (tree, header_buff, headerLen,
1552                     value_buff, valueType, valueLen);
1553                 break;
1554                                 
1555         case FN_CONNECTION:     /* Connection */
1556                 add_connection_header (tree, header_buff, headerLen,
1557                     value_buff, valueType, valueLen);
1558                 break;
1559
1560         case FN_CONTENT_LENGTH:         /* Content-Length */
1561                 add_integer_value_header (tree, header_buff, headerLen,
1562                     value_buff, valueType, valueLen,
1563                     hf_wsp_header_content_length,
1564                     headerType);
1565                 break;
1566                                 
1567         case FN_DATE:                   /* Date */
1568                 add_date_value_header (tree, header_buff, headerLen,
1569                     value_buff, valueType, valueLen,
1570                     hf_wsp_header_date, headerType);
1571                 break;
1572
1573         case FN_ETAG:                   /* Etag */
1574                 add_string_value_header (tree, header_buff, headerLen,
1575                     value_buff, valueType, valueLen,
1576                     hf_wsp_header_etag, headerType);
1577                 break;
1578
1579         case FN_EXPIRES:                /* Expires */
1580                 add_date_value_header (tree, header_buff, headerLen,
1581                     value_buff, valueType, valueLen,
1582                     hf_wsp_header_expires, headerType);
1583                 break;
1584
1585         case FN_IF_MODIFIED_SINCE:      /* If-Modified-Since */
1586                 add_date_value_header (tree, header_buff, headerLen,
1587                     value_buff, valueType, valueLen,
1588                     hf_wsp_header_if_modified_since, headerType);
1589                 break;
1590                                 
1591         case FN_LOCATION:               /* Location */
1592                 add_string_value_header (tree, header_buff, headerLen,
1593                     value_buff, valueType, valueLen,
1594                     hf_wsp_header_location, headerType);
1595                 break;
1596
1597         case FN_LAST_MODIFIED:          /* Last-Modified */
1598                 add_date_value_header (tree, header_buff, headerLen,
1599                     value_buff, valueType, valueLen,
1600                     hf_wsp_header_last_modified, headerType);
1601                 break;
1602                                 
1603         case FN_PRAGMA:                 /* Pragma */
1604                 add_pragma_header (tree, header_buff, headerLen,
1605                     value_buff, valueType, valueLen);
1606                 break;
1607                                 
1608         case FN_SERVER:                 /* Server */
1609                 add_string_value_header (tree, header_buff, headerLen,
1610                     value_buff, valueType, valueLen,
1611                     hf_wsp_header_server, headerType);
1612                 break;
1613
1614         case FN_TRANSFER_ENCODING:      /* Transfer-Encoding */
1615                 add_transfer_encoding_header (tree, header_buff, headerLen,
1616                     value_buff, valueType, valueLen);
1617                 break;
1618
1619         case FN_USER_AGENT:             /* User-Agent */
1620                 add_string_value_header (tree, header_buff, headerLen,
1621                     value_buff, valueType, valueLen,
1622                     hf_wsp_header_user_agent, headerType);
1623                 break;
1624
1625         case FN_VIA:                    /* Via */
1626                 add_string_value_header (tree, header_buff, headerLen,
1627                     value_buff, valueType, valueLen,
1628                     hf_wsp_header_via, headerType);
1629                 break;
1630
1631         case FN_WARNING:                /* Warning */
1632                 add_warning_header (tree, header_buff, headerLen,
1633                     value_buff, valueType, valueLen);
1634                 break;
1635
1636         case FN_ACCEPT_APPLICATION:     /* Accept-Application */
1637                 add_accept_application_header (tree, header_buff, headerLen,
1638                     value_buff, valueType, valueLen);
1639                 break;
1640
1641         case FN_BEARER_INDICATION:      /* Bearer-Indication */
1642                 add_integer_value_header (tree, header_buff, headerLen,
1643                     value_buff, valueType, valueLen,
1644                     hf_wsp_header_bearer_indication, headerType);
1645                 break;
1646
1647         case FN_PROFILE:                /* Profile */
1648                 add_string_value_header (tree, header_buff, headerLen,
1649                     value_buff, valueType, valueLen,
1650                     hf_wsp_header_profile, headerType);
1651                 break;
1652
1653         case FN_X_WAP_APPLICATION_ID:   /* X-Wap-Application-Id */
1654                 add_wap_application_id_header (tree, header_buff, headerLen,
1655                     value_buff, valueType, valueLen);
1656                 break;
1657
1658         case FN_CONTENT_ID:             /* Content-ID   */
1659                 add_quoted_string_value_header (tree, header_buff, headerLen,
1660                     value_buff, valueType, valueLen,
1661                     hf_wsp_header_content_ID, headerType);
1662                 break;
1663
1664         default:
1665                 proto_tree_add_text (tree, header_buff, 0, headerLen,
1666                     "Unsupported Header: %s",
1667                     val_to_str (headerType, vals_field_names, "Unknown (0x%02X)"));
1668                 break;
1669         }
1670         return offset;
1671 }
1672
1673 static int
1674 add_unknown_header (proto_tree *tree, tvbuff_t *tvb, int offset,
1675     guint8 headerType)
1676 {
1677         int headerStart;
1678         int valueStart;
1679         value_type_t valueType;
1680         int headerLen;
1681         guint valueLen;
1682         int valueOffset;
1683
1684         headerStart = offset;
1685
1686         /*
1687          * Skip the Short-Integer header type.
1688          */
1689         offset++;
1690
1691         valueStart = offset;
1692
1693         /*
1694          * Get the value type and length (or, if the type is VALUE_IN_LEN,
1695          * meaning the value is a Short-integer, get the value type
1696          * and the value itself).
1697          */ 
1698         valueType = get_value_type_len (tvb, valueStart, &valueLen,
1699             &valueOffset, &offset);
1700         headerLen = offset - headerStart;
1701
1702         proto_tree_add_text (tree, tvb, headerStart, headerLen,
1703                        "Unsupported Header (0x%02X)", headerType);
1704         return offset;
1705 }
1706
1707 static int
1708 add_application_header (proto_tree *tree, tvbuff_t *tvb, int offset)
1709 {
1710         int startOffset;
1711         guint tokenSize;
1712         const guint8 *token;
1713         value_type_t valueType;
1714         int subvalueLen;
1715         int subvalueOffset;
1716         guint secs;
1717         nstime_t timeValue;
1718         int asvOffset;
1719         guint stringSize;
1720
1721         startOffset = offset;
1722         tokenSize = tvb_strsize (tvb, startOffset);
1723         token = tvb_get_ptr (tvb, startOffset, tokenSize);
1724         offset += tokenSize;
1725
1726         /*
1727          * Special case header "X-WAP.TOD" that is sometimes followed
1728          * by a 4-byte date value.
1729          *
1730          * XXX - according to the 4-May-2000 WSP spec, X-Wap-Tod is
1731          * encoded as a well known header, with a code of 0x3F.
1732          */
1733         if (tokenSize == 10 && strncasecmp ("x-wap.tod", token, 9) == 0)
1734         {
1735                 valueType = get_value_type_len (tvb, offset,
1736                     &subvalueLen, &subvalueOffset, &offset);
1737                 if (get_integer (tvb, subvalueOffset, subvalueLen,
1738                     valueType, &secs) == 0)
1739                 {
1740                         /*
1741                          * Fill in the "struct timeval", and add it to the
1742                          * protocol tree.
1743                          * Note: this will succeed even if it's a Short-integer.
1744                          * A Short-integer would work, but, as the time values
1745                          * are UNIX seconds-since-the-Epoch value, and as
1746                          * there weren't WAP phones or Web servers back in
1747                          * late 1969/early 1970, they're unlikely to be used.
1748                          */
1749                         timeValue.secs = secs;
1750                         timeValue.nsecs = 0;
1751                         proto_tree_add_time (tree, hf_wsp_header_x_wap_tod,
1752                             tvb, startOffset, offset - startOffset, &timeValue);
1753                 }
1754                 else
1755                 {
1756                         proto_tree_add_text (tree, tvb, startOffset,
1757                             offset - startOffset,
1758                             "%s: invalid date value", token);
1759                 }
1760         }
1761         else
1762         {
1763                 asvOffset = offset;
1764                 stringSize = tvb_strsize (tvb, asvOffset);
1765                 offset += stringSize;
1766                 proto_tree_add_text (tree, tvb, startOffset,
1767                     offset - startOffset,
1768                     "%s: %s", token,
1769                     tvb_get_ptr (tvb, asvOffset, stringSize));
1770         }
1771         return offset;
1772 }
1773
1774 static void
1775 add_accept_header (proto_tree *tree, tvbuff_t *header_buff,
1776     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
1777     int valueLen)
1778 {
1779         guint contentType;
1780         const char *contentTypeStr;
1781
1782         add_content_type_value (tree, header_buff, 0, headerLen, value_buff,
1783             valueType, valueLen, hf_wsp_header_accept,
1784             hf_wsp_header_accept_str, &contentType, &contentTypeStr);
1785 }
1786
1787 static void
1788 add_accept_xxx_header (proto_tree *tree, tvbuff_t *header_buff,
1789     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
1790     int valueLen, int hf_numeric, int hf_string,
1791     const value_string *vals, const char *unknown_tag)
1792 {
1793         int offset = 0;
1794         int subvalueLen;
1795         int subvalueOffset;
1796         guint value = 0;
1797         char valString[100];
1798         const char *valMatch;
1799         guint peek;
1800         double q_value = 1.0;
1801
1802         if (valueType == VALUE_IN_LEN)
1803         {
1804                 /*
1805                  * Constrained-{charset,language} (Short-Integer).
1806                  */
1807                 proto_tree_add_uint (tree, hf_numeric,
1808                     header_buff, 0, headerLen,
1809                     valueLen);  /* valueLen is the value */
1810                 return;
1811         }
1812         if (valueType == VALUE_IS_TEXT_STRING)
1813         {
1814                 /*
1815                  * Constrained-{charset,language} (text, i.e.
1816                  * Extension-Media).
1817                  */
1818                 proto_tree_add_string (tree, hf_string,
1819                     header_buff, 0, headerLen,
1820                     tvb_get_ptr (value_buff, 0, valueLen));
1821                 return;
1822         }
1823
1824         /*
1825          * First byte had the 8th bit set.
1826          */
1827         if (valueLen == 0) {
1828                 /*
1829                  * Any-{charset,language}.
1830                  */
1831                 proto_tree_add_string (tree, hf_string,
1832                         header_buff, 0, headerLen,
1833                         "*");
1834                 return;
1835         }
1836
1837         /*
1838          * Accept-{charset,language}-general-form; Value-length, followed
1839          * by Well-known-{charset,language} or {Token-text,Text-string},
1840          * possibly followed by a Q-value.
1841          * 
1842          * Get Value-length.
1843          */
1844         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
1845             &subvalueOffset, &offset);
1846         if (valueType == VALUE_IS_TEXT_STRING)
1847         {
1848                 /*
1849                  * {Token-text,Text-string}.
1850                  */
1851                 valMatch =
1852                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen);
1853                 proto_tree_add_string (tree, hf_string,
1854                         value_buff, 0, valueLen, valMatch);
1855         } else {
1856                 /*
1857                  * Well-known-{charset,langugage}; starts with an
1858                  * Integer-value.
1859                  */
1860                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
1861                     valueType, &value) < 0)
1862                 {
1863                         valMatch = "Invalid integer";
1864                 }
1865                 else
1866                 {
1867                         valMatch = val_to_str(value, vals, unknown_tag);
1868                 }
1869         }
1870
1871         /* Any remaining data relates to Q-value */
1872         if (offset < valueLen)
1873         {
1874                 peek = tvb_get_guintvar (value_buff, offset, NULL);
1875                 if (peek <= 100) {
1876                         peek = (peek - 1) * 10;
1877                 }
1878                 else {
1879                         peek -= 100;
1880                 }
1881                 q_value = peek/1000.0;
1882         }
1883
1884         /* Build string including Q-value if present */
1885         if (q_value == 1.0)                     /* Default */
1886         {
1887                 snprintf (valString, 100, "%s", valMatch);
1888         }
1889         else
1890         {
1891                 snprintf (valString, 100, "%s; Q=%5.3f", valMatch, q_value);
1892         }
1893         /* Add string to tree */
1894         proto_tree_add_string (tree, hf_string,
1895             header_buff, 0, headerLen, valString);
1896 }
1897
1898 static void
1899 add_accept_ranges_header (proto_tree *tree, tvbuff_t *header_buff,
1900     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
1901     int valueLen)
1902 {
1903         if (valueType == VALUE_IN_LEN)
1904         {
1905                 /*
1906                  * Must be 0 (None) or 1 (Bytes) (the 8th bit was stripped
1907                  * off).
1908                  */
1909                 proto_tree_add_uint (tree, hf_wsp_header_accept_ranges,
1910                     header_buff, 0, headerLen,
1911                     valueLen);  /* valueLen is the value */
1912                 return;
1913         }
1914         if (valueType == VALUE_IS_TEXT_STRING)
1915         {
1916                 /*
1917                  * Token-text.
1918                  */
1919                 proto_tree_add_string (tree, hf_wsp_header_accept_ranges_str,
1920                     header_buff, 0, headerLen,
1921                     tvb_get_ptr (value_buff, 0, valueLen));
1922                 return;
1923         }
1924
1925         /*
1926          * Not valid.
1927          */
1928         fprintf(stderr, "dissect_wsp: Accept-Ranges is neither None, Bytes, nor Token-text\n");
1929         return;
1930 }
1931
1932 static void
1933 add_cache_control_header (proto_tree *tree, tvbuff_t *header_buff,
1934     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
1935     int valueLen)
1936 {
1937         int offset = 0;
1938         int subvalueLen;
1939         int subvalueOffset;
1940         guint value;
1941         proto_item *ti;
1942         proto_tree *parameter_tree;
1943         proto_tree *field_names_tree;
1944         guint delta_secs;
1945
1946         if (valueType == VALUE_IN_LEN)
1947         {
1948                 /*
1949                  * No-cache, No-store, Max-age, Max-stale, Min-fresh,
1950                  * Only-if-cached, Public, Private, No-transform,
1951                  * Must-revalidate, Proxy-revalidate, or S-maxage.
1952                  */
1953                 proto_tree_add_uint (tree, hf_wsp_header_cache_control,
1954                     header_buff, 0, headerLen,
1955                     valueLen);  /* valueLen is the value */
1956                 return;
1957         }
1958         if (valueType == VALUE_IS_TEXT_STRING)
1959         {
1960                 /*
1961                  * Cache-extension.
1962                  */
1963                 proto_tree_add_string (tree, hf_wsp_header_cache_control_str,
1964                     header_buff, 0, headerLen,
1965                     tvb_get_ptr (value_buff, 0, valueLen));
1966                 return;
1967         }
1968
1969         /*
1970          * Value-length Cache-directive.
1971          * Get first field of Cache-directive.
1972          */
1973         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
1974             &subvalueOffset, &offset);
1975         if (valueType == VALUE_IS_TEXT_STRING)
1976         {
1977                 /*
1978                  * Cache-extension Parameter.
1979                  */
1980                 ti = proto_tree_add_string (tree, hf_wsp_header_cache_control_str,
1981                     header_buff, 0, headerLen,
1982                     tvb_get_ptr (value_buff, 0, valueLen));
1983                 parameter_tree = proto_item_add_subtree (ti,
1984                     ett_header_cache_control_parameters);
1985
1986                 /*
1987                  * Process the rest of the value as parameters.
1988                  */
1989                 while (tvb_reported_length_remaining (value_buff, offset) > 0) {
1990                         offset = add_parameter (parameter_tree, value_buff,
1991                             offset);
1992                 }
1993                 return;
1994         }
1995         if (get_integer (value_buff, subvalueOffset, subvalueLen, valueType,
1996             &value) < 0)
1997         {
1998                 proto_tree_add_text (tree, header_buff, 0, headerLen,
1999                     "Invalid Cache-Control Cache-directive value");
2000         }
2001         else
2002         {
2003                 switch (value) {
2004
2005                 case NO_CACHE:
2006                 case PRIVATE:
2007                         /*
2008                          * Loop, processing Field-names.
2009                          */
2010                         ti = proto_tree_add_uint (tree,
2011                             hf_wsp_header_cache_control,
2012                             header_buff, 0, headerLen,
2013                             value);
2014                         field_names_tree = proto_item_add_subtree (ti,
2015                             ett_header_cache_control_field_names);
2016                         while (tvb_reported_length_remaining (value_buff, offset)
2017                             > 0) {
2018                                 offset = add_cache_control_field_name (tree,
2019                                     value_buff, offset, value);
2020                         }
2021                         break;
2022
2023                 case MAX_AGE:
2024                 case MAX_STALE:
2025                 case MIN_FRESH:
2026                 case S_MAXAGE:
2027                         /*
2028                          * Get Delta-second-value.
2029                          */
2030                         valueType = get_value_type_len (value_buff, offset,
2031                             &subvalueLen, &subvalueOffset, &offset);
2032                         if (get_integer (value_buff, subvalueOffset,
2033                             subvalueLen, valueType, &delta_secs) < 0)
2034                         {
2035                                 proto_tree_add_text (tree,
2036                                     header_buff, 0, headerLen,
2037                                     "Invalid Cache-Control %s Delta-second-value",
2038                                     match_strval (value, vals_cache_control));
2039                         }
2040                         else 
2041                         {
2042                                 proto_tree_add_uint_format (tree,
2043                                     hf_wsp_header_cache_control,
2044                                     header_buff, 0, headerLen,
2045                                     value,
2046                                     "Cache-Control: %s %u secs",
2047                                     match_strval (value, vals_cache_control),
2048                                     delta_secs);
2049                         }
2050                         break;
2051
2052                 default:
2053                         /*
2054                          * This should not happen, but handle it anyway.
2055                          */
2056                         proto_tree_add_uint (tree,
2057                             hf_wsp_header_cache_control,
2058                             header_buff, 0, headerLen,
2059                             value);
2060                         break;
2061                 }
2062         }
2063 }
2064
2065 static int
2066 add_cache_control_field_name (proto_tree *tree, tvbuff_t *value_buff,
2067     int offset, guint cache_control_value)
2068 {
2069         value_type_t valueType;
2070         int startOffset;
2071         int subvalueLen;
2072         int subvalueOffset;
2073
2074         startOffset = offset;
2075         valueType = get_value_type_len (value_buff, offset,
2076             &subvalueLen, &subvalueOffset, &offset);
2077         if (valueType == VALUE_IS_TEXT_STRING)
2078         {
2079                 /*
2080                  * Token-text.
2081                  */
2082                 proto_tree_add_item (tree, 
2083                     hf_wsp_header_cache_control_field_name_str,
2084                     value_buff, startOffset, offset - startOffset,
2085                     bo_little_endian);
2086         }
2087         else if (valueType == VALUE_IN_LEN)
2088         {
2089                 /*
2090                  * Short-integer Field-name.
2091                  */
2092                 proto_tree_add_uint (tree,
2093                     hf_wsp_header_cache_control_field_name,
2094                     value_buff, startOffset, offset - startOffset,
2095                     subvalueLen);
2096         }
2097         else
2098         {
2099                 /*
2100                  * Long-integer - illegal.
2101                  */
2102                 proto_tree_add_text (tree,
2103                     value_buff, startOffset, offset - startOffset,
2104                     "Invalid Cache-Control %s Field-name",
2105                     match_strval (cache_control_value, vals_cache_control));
2106         }       
2107         return offset;
2108 }
2109
2110 static void
2111 add_connection_header (proto_tree *tree, tvbuff_t *header_buff,
2112     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2113     int valueLen)
2114 {
2115         int offset = 0;
2116
2117         if (valueType == VALUE_LEN_SUPPLIED)
2118         {
2119                 /*
2120                  * Invalid.
2121                  */
2122                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2123                     "Invalid Connection value");
2124                 return;
2125         }
2126         if (valueType == VALUE_IS_TEXT_STRING)
2127         {
2128                 /*
2129                  * Token-text.
2130                  */
2131                 proto_tree_add_string (tree,
2132                     hf_wsp_header_connection_str,
2133                     header_buff, 0, headerLen,
2134                     tvb_get_ptr (value_buff, 0, valueLen));
2135                 return;
2136         }
2137
2138         /*
2139          * First byte had the 8th bit set.
2140          */
2141         if (valueLen == 0) {
2142                 /*
2143                  * Close.
2144                  */
2145                 proto_tree_add_uint (tree, hf_wsp_header_connection,
2146                     header_buff, offset, headerLen, valueLen);
2147                 return;
2148         }
2149
2150         /*
2151          * Invalid.
2152          */
2153         proto_tree_add_text (tree, header_buff, 0, headerLen,
2154             "Invalid Connection value");
2155 }
2156
2157 static void
2158 add_pragma_header (proto_tree *tree, tvbuff_t *header_buff,
2159     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2160     int valueLen)
2161 {
2162         int offset = 0;
2163         int subvalueLen;
2164         int subvalueOffset;
2165
2166         if (valueType == VALUE_IN_LEN)
2167         {
2168                 /*
2169                  * Invalid.
2170                  */
2171                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2172                     "Invalid Pragma");
2173                 return;
2174         }
2175         if (valueType == VALUE_IS_TEXT_STRING)
2176         {
2177                 /*
2178                  * Invalid?
2179                  */
2180                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2181                     "Invalid Pragma");
2182                 return;
2183         }
2184
2185         /*
2186          * First byte had the 8th bit set.
2187          */
2188         if (valueLen == 0) {
2189                 /*
2190                  * No-cache.
2191                  */
2192                 proto_tree_add_string (tree, hf_wsp_header_pragma,
2193                     header_buff, 0, headerLen, "No-cache");
2194                 return;
2195         }
2196
2197         /*
2198          * Value-length, followed by Parameter.
2199          * 
2200          * Get Value-length.
2201          */
2202         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
2203             &subvalueOffset, &offset);
2204         if (valueType == VALUE_IS_TEXT_STRING)
2205         {
2206                 /*
2207                  * Parameter - a text string.
2208                  */
2209                 proto_tree_add_string (tree, hf_wsp_header_pragma,
2210                     header_buff, 0, headerLen,
2211                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
2212         } else {
2213                 /*
2214                  * Parameter - numeric; illegal?
2215                  */
2216                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2217                     "Invalid Pragma");
2218         }
2219 }
2220
2221 static void
2222 add_transfer_encoding_header (proto_tree *tree, tvbuff_t *header_buff,
2223     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2224     int valueLen)
2225 {
2226         int offset = 0;
2227
2228         if (valueType == VALUE_LEN_SUPPLIED)
2229         {
2230                 /*
2231                  * Invalid.
2232                  */
2233                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2234                     "Invalid Transfer-Encoding value");
2235                 return;
2236         }
2237         if (valueType == VALUE_IS_TEXT_STRING)
2238         {
2239                 /*
2240                  * Token-text.
2241                  */
2242                 proto_tree_add_string (tree,
2243                     hf_wsp_header_transfer_encoding_str,
2244                     header_buff, 0, headerLen,
2245                     tvb_get_ptr (value_buff, 0, valueLen));
2246                 return;
2247         }
2248
2249         /*
2250          * First byte had the 8th bit set.
2251          */
2252         if (valueLen == 0) {
2253                 /*
2254                  * Chunked.
2255                  */
2256                 proto_tree_add_uint (tree, hf_wsp_header_transfer_encoding,
2257                     header_buff, offset, headerLen, valueLen);
2258                 return;
2259         }
2260
2261         /*
2262          * Invalid.
2263          */
2264         proto_tree_add_text (tree, header_buff, 0, headerLen,
2265             "Invalid Transfer Encoding value");
2266 }
2267
2268 static void
2269 add_warning_header (proto_tree *tree, tvbuff_t *header_buff,
2270     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2271     int valueLen)
2272 {
2273         int offset = 0;
2274         proto_item *ti;
2275         proto_tree *warning_tree;
2276         int subvalueLen;
2277         int subvalueOffset;
2278
2279         /*
2280          * Put the items under a header.
2281          * XXX - make the text of the item summarize the elements.
2282          */
2283         ti = proto_tree_add_item (tree, hf_wsp_header_warning,
2284             header_buff, 0, headerLen, bo_little_endian);
2285         warning_tree = proto_item_add_subtree(ti, ett_header_warning);
2286         
2287         if (valueType == VALUE_IN_LEN)
2288         {
2289                 /*
2290                  * Warn-code (Short-integer).
2291                  */
2292                 proto_tree_add_uint (warning_tree, hf_wsp_header_warning_code,
2293                     header_buff, 0, headerLen,
2294                     valueLen);  /* valueLen is the value */
2295                 return;
2296         }
2297         if (valueType == VALUE_IS_TEXT_STRING)
2298         {
2299                 /*
2300                  * Invalid.
2301                  */
2302                 proto_tree_add_text (warning_tree, header_buff, 0, headerLen,
2303                     "Invalid Warning (all text)");
2304                 return;
2305         }
2306
2307         /*
2308          * Warning-value; Warn-code, followed by Warn-agent, followed by
2309          * Warn-text.
2310          */
2311         /*
2312          * Get Short-integer Warn-code.
2313          */
2314         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2315             &subvalueOffset, &offset);
2316         if (valueType != VALUE_IN_LEN)
2317         {
2318                 /*
2319                  * Not a Short-integer.
2320                  */
2321                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2322                     subvalueLen, "Invalid Warn-code (not a Short-integer)");
2323                 return;
2324         }
2325         proto_tree_add_uint (warning_tree, hf_wsp_header_warning_code,
2326             value_buff, subvalueOffset, 1,
2327             subvalueLen);       /* subvalueLen is the value */
2328
2329         /*
2330          * Warn-agent; must be text.
2331          */
2332         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2333             &subvalueOffset, &offset);
2334         if (valueType != VALUE_IS_TEXT_STRING)
2335         {
2336                 /*
2337                  * Not text.
2338                  */
2339                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2340                     subvalueLen, "Invalid Warn-agent (not a text string)");
2341                 return;
2342         }
2343         proto_tree_add_item (warning_tree,
2344                 hf_wsp_header_warning_agent,
2345                 value_buff, subvalueOffset, subvalueLen, bo_little_endian);
2346
2347         /*
2348          * Warn-text; must be text.
2349          */
2350         valueType = get_value_type_len (value_buff, offset, &subvalueLen,
2351             &subvalueOffset, &offset);
2352         if (valueType != VALUE_IS_TEXT_STRING)
2353         {
2354                 /*
2355                  * Not text.
2356                  */
2357                 proto_tree_add_text (warning_tree, value_buff, subvalueOffset,
2358                     subvalueLen, "Invalid Warn-text (not a text string)");
2359                 return;
2360         }
2361         proto_tree_add_item (warning_tree,
2362                 hf_wsp_header_warning_text,
2363                 value_buff, subvalueOffset, subvalueLen, bo_little_endian);
2364 }
2365
2366 static void
2367 add_accept_application_header (proto_tree *tree, tvbuff_t *header_buff,
2368     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2369     int valueLen)
2370 {
2371         guint value;
2372
2373         if (valueType == VALUE_IN_LEN)
2374         {
2375                 /*
2376                  * Application-id-value; numeric, so it's App-assigned-code.
2377                  */
2378                 proto_tree_add_uint (tree, hf_wsp_header_accept_application,
2379                     header_buff, 0, headerLen,
2380                     valueLen);  /* valueLen is the value */
2381                 return;
2382         }
2383         if (valueType == VALUE_IS_TEXT_STRING)
2384         {
2385                 /*
2386                  * Uri-value.
2387                  */
2388                 proto_tree_add_string (tree, hf_wsp_header_accept_application_str,
2389                     header_buff, 0, headerLen,
2390                     tvb_get_ptr (value_buff, 0, valueLen));
2391                 return;
2392         }
2393
2394         /*
2395          * First byte had the 8th bit set.
2396          */
2397         if (valueLen == 0) {
2398                 /*
2399                  * Any-application.
2400                  */
2401                 proto_tree_add_string (tree, hf_wsp_header_accept_application_str,
2402                         header_buff, 0, headerLen,
2403                         "*");
2404                 return;
2405         }
2406
2407         /*
2408          * Integer-value, hence App-assigned-code.
2409          */
2410         if (get_integer (value_buff, 0, valueLen, valueType, &value) < 0)
2411         {
2412                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2413                         "Invalid Accept-Application App-assigned-code");
2414         }
2415         else
2416         {
2417                 proto_tree_add_uint (tree, hf_wsp_header_accept_application,
2418                     header_buff, 0, headerLen, value);
2419         }
2420 }
2421
2422 static void
2423 add_wap_application_id_header (proto_tree *tree, tvbuff_t *header_buff,
2424     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2425     int valueLen)
2426 {
2427         if (valueType == VALUE_IN_LEN)
2428         {
2429                 /*
2430                  * Must application-id (the 8th bit was stripped off).
2431                  */
2432                 proto_tree_add_uint (tree, hf_wsp_header_wap_application_id,
2433                     header_buff, 0, headerLen,
2434                     valueLen);  /* valueLen is the value */
2435                 return;
2436         }
2437         if (valueType == VALUE_IS_TEXT_STRING)
2438         {
2439                 /*
2440                  * Token-text.
2441                  */
2442                 proto_tree_add_string (tree, hf_wsp_header_wap_application_id_str,
2443                     header_buff, 0, headerLen,
2444                     tvb_get_ptr (value_buff, 0, valueLen));
2445                 return;
2446         }
2447
2448         /*
2449          * Not valid.
2450          */
2451         fprintf(stderr, "dissect_wsp: Suprising format of X-Wap-Application-Id\n");
2452         return;
2453 }
2454
2455 static void
2456 add_capabilities (proto_tree *tree, tvbuff_t *tvb, int type)
2457 {
2458         proto_item *ti;
2459         proto_tree *wsp_capabilities;
2460         guint offset = 0;
2461         guint offsetStr = 0;
2462         guint capabilitiesLen = tvb_reported_length (tvb);
2463         guint capabilitiesStart = 0;
2464         guint peek = 0;
2465         guint length = 0;
2466         guint value = 0;
2467         guint i;
2468         int ret;
2469         char valString[200];
2470
2471 #ifdef DEBUG
2472         fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, capabilitiesLen);
2473 #endif
2474
2475         /* End of buffer */
2476         if (capabilitiesLen <= 0)
2477         {
2478                 fprintf (stderr, "dissect_wsp: Capabilities = 0\n");
2479                 return;
2480         }
2481
2482 #ifdef DEBUG
2483         fprintf (stderr, "dissect_wsp: capabilities to process\n");
2484 #endif
2485
2486         ti = proto_tree_add_item (tree, hf_wsp_capabilities_section,tvb,offset,capabilitiesLen,bo_little_endian);
2487         wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
2488
2489         /* Parse Headers */
2490
2491         while (offset < capabilitiesLen)
2492         {
2493                 /* Loop round each header */
2494                 capabilitiesStart = offset;
2495                 length = tvb_get_guint8 (tvb, capabilitiesStart);
2496
2497                 if (length >= 127)              /* length */
2498                 {
2499 #ifdef DEBUG
2500                         fprintf (stderr, "dissect_wsp: capabilities length invalid %d\n",length);
2501 #endif
2502                         offset+=length;
2503                         continue;
2504                 }
2505                 offset++;
2506                 peek = tvb_get_guint8 (tvb, offset);
2507                 offset++;
2508                 switch (peek & 0x7f)
2509                 {
2510                         case 0x00 : /* Client-SDU-Size */
2511                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2512                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_client_SDU, tvb, capabilitiesStart, length+1, value);
2513                                 break;
2514                         case 0x01 : /* Server-SDU-Size */
2515                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2516                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_server_SDU, tvb, capabilitiesStart, length+1, value);
2517                                 break;
2518                         case 0x02 : /* Protocol Options */ 
2519                                 value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
2520                                 i = 0;
2521                                 valString[0]=0;
2522                                 if (value & 0x80)
2523                                 {
2524                                         ret = snprintf(valString+i,200-i,"%s","(Confirmed push facility) ");
2525                                         if (ret == -1) {
2526                                                 /*
2527                                                  * Some versions of snprintf
2528                                                  * return -1 if they'd
2529                                                  * truncate the output.
2530                                                  */
2531                                                 goto add_string;
2532                                         }
2533                                         i += ret;
2534                                 }
2535                                 if (value & 0x40)
2536                                 {
2537                                         if (i >= 200) {
2538                                                 /* No more room. */
2539                                                 goto add_string;
2540                                         }
2541                                         ret = snprintf(valString+i,200-i,"%s","(Push facility) ");
2542                                         if (ret == -1) {
2543                                                 /*
2544                                                  * Some versions of snprintf
2545                                                  * return -1 if they'd
2546                                                  * truncate the output.
2547                                                  */
2548                                                 goto add_string;
2549                                         }
2550                                         i += ret;
2551                                 }
2552                                 if (value & 0x20)
2553                                 {
2554                                         if (i >= 200) {
2555                                                 /* No more room. */
2556                                                 goto add_string;
2557                                         }
2558                                         ret = snprintf(valString+i,200-i,"%s","(Session resume facility) ");
2559                                         if (ret == -1) {
2560                                                 /*
2561                                                  * Some versions of snprintf
2562                                                  * return -1 if they'd
2563                                                  * truncate the output.
2564                                                  */
2565                                                 goto add_string;
2566                                         }
2567                                         i += ret;
2568                                 }
2569                                 if (value & 0x10)
2570                                 {
2571                                         if (i >= 200) {
2572                                                 /* No more room. */
2573                                                 goto add_string;
2574                                         }
2575                                         ret = snprintf(valString+i,200-i,"%s","(Acknowledgement headers) ");
2576                                         if (ret == -1) {
2577                                                 /*
2578                                                  * Some versions of snprintf
2579                                                  * return -1 if they'd
2580                                                  * truncate the output.
2581                                                  */
2582                                                 goto add_string;
2583                                         }
2584                                         i += ret;
2585                                 }
2586                         add_string:
2587                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_protocol_opt, tvb, capabilitiesStart, length+1, valString);
2588                                 break;
2589                         case 0x03 : /* Method-MOR */ 
2590                                 value = tvb_get_guint8(tvb, offset);
2591                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_method_MOR, tvb, capabilitiesStart, length+1, value);
2592                                 break;
2593                         case 0x04 : /* Push-MOR */ 
2594                                 value = tvb_get_guint8(tvb, offset);
2595                                 proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_push_MOR, tvb, capabilitiesStart, length+1, value);
2596                                 break;
2597                                 break;
2598                         case 0x05 : /* Extended Methods */ 
2599                                 offsetStr = offset;
2600                                 offset++;
2601                                 add_capability_vals(tvb, (type == CONNECT),
2602                                     offsetStr, length, capabilitiesStart,
2603                                     valString, sizeof valString);
2604                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_extended_methods, tvb, capabilitiesStart, length+1, valString);
2605                                 break;
2606                         case 0x06 : /* Header Code Pages */ 
2607                                 offsetStr = offset;
2608                                 offset++;
2609                                 add_capability_vals(tvb, (type == CONNECT),
2610                                     offsetStr, length, capabilitiesStart,
2611                                     valString, sizeof valString);
2612                                 proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_header_code_pages, tvb, capabilitiesStart, length+1, valString);
2613                                 break;
2614                         case 0x07 : /* Aliases */
2615                                 break;
2616                         default:
2617                                 proto_tree_add_text (wsp_capabilities, tvb , capabilitiesStart, length+1,
2618                                        "Unsupported Header (0x%02X)", peek & 0x7F);
2619                                 break;
2620                 }
2621                 offset=capabilitiesStart+length+1;
2622         }
2623 }
2624
2625 static void
2626 add_capability_vals(tvbuff_t *tvb, gboolean add_string, int offsetStr,
2627     guint length, guint capabilitiesStart, char *valString,
2628     size_t valStringSize)
2629 {
2630         guint i;
2631         int ret;
2632         guint value;
2633         guint8 c;
2634
2635         i = 0;
2636         while ((offsetStr-capabilitiesStart) <= length)
2637         {
2638                 value = tvb_get_guint8(tvb, offsetStr);
2639                 if (i >= valStringSize) {
2640                         /* No more room. */
2641                         break;
2642                 }
2643                 if (add_string)
2644                 {
2645                         ret = snprintf(valString+i,valStringSize-i,
2646                             "(%d - ",value);
2647                 }
2648                 else
2649                 {
2650                         ret = snprintf(valString+i,valStringSize-i,"(%d) ",
2651                             value);
2652                 }
2653                 if (ret == -1) {
2654                         /*
2655                          * Some versions of snprintf return -1
2656                          * if they'd truncate the output.
2657                          */
2658                         break;
2659                 }
2660                 i += ret;
2661                 offsetStr++;
2662                 if (add_string)
2663                 {
2664                         for (;(c = tvb_get_guint8(tvb, offsetStr))
2665                             && i < valStringSize - 1; i++,offsetStr++)
2666                                 valString[i] = c;
2667                         offsetStr++;
2668                         if (i < valStringSize - 2) {
2669                                 valString[i++] = ')';
2670                                 valString[i++] = ' ';
2671                         }
2672                 }
2673         }
2674         valString[i] = '\0';
2675 }
2676
2677 static value_type_t
2678 get_value_type_len (tvbuff_t *tvb, int offset, guint *valueLen,
2679     int *valueOffset, int *nextOffset)
2680 {
2681         guint8 peek;
2682         guint32 len;
2683         guint count;
2684
2685         /* Get value part of header */
2686         peek = tvb_get_guint8 (tvb, offset);
2687         if (peek <= 30)
2688         {
2689                 /*
2690                  * The value follows "peek", and is "peek" octets long.
2691                  */
2692 #ifdef DEBUG
2693                 fprintf (stderr, "dissect_wsp: Looking for %d octets\n", peek);
2694 #endif
2695                 len = peek;
2696                 *valueLen = len;        /* Length of value */
2697                 offset++;               /* Skip the length */
2698                 *valueOffset = offset;  /* Offset of value */
2699                 offset += len;          /* Skip the value */
2700                 *nextOffset = offset;   /* Offset after value */
2701                 return VALUE_LEN_SUPPLIED;
2702         }
2703         else if (peek == 31)
2704         {
2705                 /*
2706                  * A uintvar giving the length of the value follows
2707                  * "peek", and the value follows that.
2708                  */
2709 #ifdef DEBUG
2710                 fprintf (stderr, "dissect_wsp: Looking for uintvar octets\n");
2711 #endif
2712                 offset++;               /* Skip the uintvar indicator */
2713                 count = 0;              /* Initialise count */
2714                 len = tvb_get_guintvar (tvb, offset, &count);
2715                 *valueLen = len;        /* Length of value */
2716                 offset += count;        /* Skip the length */
2717                 *valueOffset = offset;  /* Offset of value */
2718                 offset += len;          /* Skip the value */
2719                 *nextOffset = offset;   /* Offset after value */
2720                 return VALUE_LEN_SUPPLIED;
2721         }
2722         else if (peek <= 127)
2723         {
2724                 /*
2725                  * The value is a NUL-terminated string, and "peek"
2726                  * is the first octet of the string.
2727                  */
2728 #ifdef DEBUG
2729                 fprintf (stderr, "dissect_wsp: Looking for NUL-terminated string\n");
2730 #endif
2731                 len = tvb_strsize (tvb, offset);
2732                 *valueLen = len;        /* Length of value */
2733                 *valueOffset = offset;  /* Offset of value */
2734                 offset += len;          /* Skip the value */
2735                 *nextOffset = offset;   /* Offset after value */
2736                 return VALUE_IS_TEXT_STRING;
2737         }
2738         else
2739         {
2740                 /*
2741                  * "peek", with the 8th bit stripped off, is the value.
2742                  */
2743 #ifdef DEBUG
2744                 fprintf (stderr, "dissect_wsp: Value is %d\n", (peek & 0x7F));
2745 #endif
2746                 *valueLen = peek & 0x7F; /* Return the value itself */
2747                 *valueOffset = offset;  /* Offset of value */
2748                 offset++;               /* Skip the value */
2749                 *nextOffset = offset;   /* Offset after value */
2750                 return VALUE_IN_LEN;
2751         }
2752 }
2753
2754 static guint
2755 get_uintvar (tvbuff_t *tvb, guint offset, guint offsetEnd)
2756 {
2757         guint value = 0;
2758         guint octet;
2759
2760         do
2761         {
2762                 octet = tvb_get_guint8 (tvb, offset);
2763                 offset++;
2764                 value <<= 7;
2765                 value += octet & 0x7f;
2766         }
2767         while ((offsetEnd > offset) && (octet & 0x80));
2768         return value;
2769 }
2770
2771 static void
2772 add_content_type_value (proto_tree *tree, tvbuff_t *header_buff,
2773     int headerOffset, int headerLen, tvbuff_t *value_buff,
2774     value_type_t valueType, int valueLen, int hf_numeric, int hf_string,
2775     guint *contentTypep, const char **contentTypeStrp)
2776 {
2777         proto_item *ti;
2778         proto_tree *parameter_tree;
2779         const char *contentTypeStr;
2780         int offset;
2781         int subvalueLen;
2782         int subvalueOffset;
2783         guint value;
2784
2785         if (valueType == VALUE_IN_LEN)
2786         {
2787                 /*
2788                  * Constrained-media (Short-Integer).
2789                  */
2790                 proto_tree_add_uint (tree, hf_numeric,
2791                     header_buff, headerOffset, headerLen,
2792                     valueLen);  /* valueLen is the value */
2793
2794                 /*
2795                  * Return the numerical value, and a null string value
2796                  * indicating that the value is numerical.
2797                  */
2798                 *contentTypep = valueLen;
2799                 *contentTypeStrp = NULL;
2800                 return;
2801         }
2802         if (valueType == VALUE_IS_TEXT_STRING)
2803         {
2804                 /*
2805                  * Constrained-media (text, i.e. Extension-Media).
2806                  */
2807                 contentTypeStr = tvb_get_ptr (value_buff, 0, valueLen);
2808                 proto_tree_add_string (tree, hf_string,
2809                     header_buff, headerOffset, headerLen,
2810                     contentTypeStr);
2811
2812                 /*
2813                  * Return the string value, and set the numerical value
2814                  * to 0 (as it shouldn't be used).
2815                  */
2816                 *contentTypep = 0;
2817                 *contentTypeStrp = contentTypeStr;
2818                 return;
2819         }
2820
2821         /*
2822          * Content-general-form; Value-length, followed by Media-range,
2823          * followed by optional Accept-parameters.
2824          *
2825          * Get Value-length.
2826          */
2827         valueType = get_value_type_len (value_buff, 0, &subvalueLen,
2828             &subvalueOffset, &offset);
2829         if (valueType == VALUE_IS_TEXT_STRING)
2830         {
2831                 /*
2832                  * Extension-Media; value is a string.
2833                  */
2834                 contentTypeStr =
2835                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen);
2836                 ti = proto_tree_add_string (tree, hf_string, header_buff,
2837                     headerOffset, headerLen, contentTypeStr);
2838
2839                 /*
2840                  * Return the string value, and set the numerical value
2841                  * to 0 (as it shouldn't be used).
2842                  */
2843                 *contentTypep = 0;
2844                 *contentTypeStrp = contentTypeStr;
2845         }
2846         else
2847         {
2848                 /*
2849                  * Well-known-media; value is an Integer.
2850                  */
2851                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
2852                     valueType, &value) < 0)
2853                 {
2854                         proto_tree_add_text (tree, header_buff,
2855                             headerOffset, headerLen,
2856                             "Invalid integer for Well-known-media");
2857
2858                         /*
2859                          * Content type is invalid.
2860                          * Don't try to parse the rest of the value.
2861                          */
2862                         *contentTypep = 0;
2863                         *contentTypeStrp = NULL;
2864                         return;
2865                 }
2866                 ti = proto_tree_add_uint (tree, hf_numeric,
2867                     header_buff, headerOffset, headerLen, value);
2868
2869                 /*
2870                  * Return the numerical value, and a null string value
2871                  * indicating that the value is numerical.
2872                  */
2873                 *contentTypep = value;
2874                 *contentTypeStrp = NULL;
2875         }
2876
2877         /*
2878          * Process the rest of the value as parameters.
2879          */
2880         parameter_tree = proto_item_add_subtree(ti,
2881             ett_content_type_parameters);
2882         while (tvb_reported_length_remaining (value_buff, offset) > 0)
2883                 offset = add_parameter (parameter_tree, value_buff, offset);
2884 }
2885
2886 guint
2887 add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset,
2888     guint *contentTypep, const char **contentTypeStrp)
2889 {
2890         int valueStart;
2891         value_type_t valueType;
2892         int valueTypeLen;
2893         guint valueLen;
2894         int valueOffset;
2895         tvbuff_t *value_buff;
2896
2897         valueStart = offset;
2898
2899         /*
2900          * Get the value type and length (or, if the type is VALUE_IN_LEN,
2901          * meaning the value is a Short-integer, get the value type
2902          * and the value itself).
2903          */ 
2904         valueType = get_value_type_len (tvb, valueStart, &valueLen,
2905             &valueOffset, &offset);
2906         valueTypeLen = offset - valueStart;
2907
2908         /*
2909          * Get a tvbuff for the value.
2910          * XXX - can valueLen be 0?
2911          * XXX - cut the actual length short so that it doesn't run
2912          * past the actual length of tvb.
2913          */
2914         if (valueType != VALUE_IN_LEN) {
2915                 value_buff = tvb_new_subset (tvb, valueOffset, valueLen,
2916                     valueLen);
2917         } else {
2918                 /*
2919                  * XXX - when the last dissector is tvbuffified,
2920                  * so that NULL is no longer a valid tvb pointer
2921                  * value in "proto_tree_add" calls, just
2922                  * set "value_buff" to NULL.
2923                  *
2924                  * XXX - can we already do that?  I.e., will that
2925                  * cause us always to crash if we mistakenly try
2926                  * to fetch the value of a VALUE_IN_LEN item?
2927                  */
2928                 value_buff = tvb_new_subset (tvb, valueStart, 0, 0);
2929         }
2930
2931         add_content_type_value (tree, tvb, valueStart, valueTypeLen, value_buff,
2932             valueType, valueLen, hf_wsp_content_type,
2933             hf_wsp_content_type_str, contentTypep, contentTypeStrp);
2934
2935         return offset;
2936 }
2937
2938 static void
2939 add_integer_value_header (proto_tree *tree, tvbuff_t *header_buff,
2940     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2941     int valueLen, int hf_numeric, guint8 headerType)
2942 {
2943         guint value;
2944
2945         if (get_integer (value_buff, 0, valueLen, valueType, &value) < 0)
2946         {
2947                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2948                     "Invalid %s integer value",
2949                     match_strval (headerType, vals_field_names));
2950         }
2951         else
2952         {
2953                 proto_tree_add_uint (tree, hf_numeric,
2954                     header_buff, 0, headerLen, value);
2955         }
2956 }
2957
2958 static void
2959 add_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
2960     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2961     int valueLen, int hf_string, guint8 headerType)
2962 {
2963         if (valueType != VALUE_IS_TEXT_STRING)
2964         {
2965                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2966                     "Invalid %s string value",
2967                     match_strval (headerType, vals_field_names));
2968         }
2969         else
2970         {
2971                 proto_tree_add_string (tree, hf_string, header_buff,
2972                         0, headerLen, tvb_get_ptr (value_buff, 0, valueLen));
2973         }
2974 }
2975
2976 static void
2977 add_quoted_string_value_header (proto_tree *tree, tvbuff_t *header_buff,
2978     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2979     int valueLen, int hf_string, guint8 headerType)
2980 {
2981         if (valueType != VALUE_IS_TEXT_STRING)
2982         {
2983                 proto_tree_add_text (tree, header_buff, 0, headerLen,
2984                     "Invalid %s quoted string value",
2985                     match_strval (headerType, vals_field_names));
2986         }
2987         else
2988         {
2989                 proto_tree_add_string (tree, hf_string, header_buff,
2990                         0, headerLen, tvb_get_ptr (value_buff, 1, valueLen - 1));
2991         }
2992 }
2993
2994 /* Utility function to add a date value to the protocol tree */
2995 static void
2996 add_date_value_header (proto_tree *tree, tvbuff_t *header_buff,
2997     int headerLen, tvbuff_t *value_buff, value_type_t valueType,
2998     int valueLen, int hf_time, guint8 headerType)
2999 {
3000         guint secs;
3001         nstime_t timeValue;
3002
3003         /* Attempt to get the date value from the buffer */
3004         if (get_integer (value_buff, 0, valueLen, valueType, &secs) == 0)
3005         {
3006                 /*
3007                  * Fill in the "struct timeval", and add it to the
3008                  * protocol tree.
3009                  * Note: this will succeed even if it's a Short-integer.
3010                  * A Short-integer would work, but, as the time values
3011                  * are UNIX seconds-since-the-Epoch value, and as
3012                  * there weren't WAP phones or Web servers back in
3013                  * late 1969/early 1970, they're unlikely to be used.
3014                  */
3015                 timeValue.secs = secs;
3016                 timeValue.nsecs = 0;
3017                 proto_tree_add_time (tree, hf_time, header_buff, 0,
3018                         headerLen, &timeValue);
3019         }
3020         else
3021         {
3022                 proto_tree_add_text (tree, header_buff, 0, headerLen,
3023                     "Invalid %s date value",
3024                     match_strval (headerType, vals_field_names));
3025         }
3026 }
3027
3028 static int
3029 add_parameter (proto_tree *tree, tvbuff_t *value_buff, int offset)
3030 {
3031         int startOffset;
3032         value_type_t valueType;
3033         int subvalueLen;
3034         int subvalueOffset;
3035         guint value;
3036
3037         startOffset = offset;
3038         valueType = get_value_type_len (value_buff, offset,
3039             &subvalueLen, &subvalueOffset, &offset);
3040         if (valueType == VALUE_IS_TEXT_STRING)
3041         {
3042                 /*
3043                  * Untyped-parameter.
3044                  */
3045                 offset = add_untyped_parameter (tree, value_buff, startOffset, offset);
3046                 return offset;
3047         }
3048
3049         /*
3050          * Well-known-parameter-token.
3051          */
3052         if (get_integer (value_buff, subvalueOffset,
3053             subvalueLen, valueType, &value) < 0)
3054         {
3055                 proto_tree_add_text (tree, value_buff, startOffset,
3056                     offset - startOffset,
3057                     "Invalid Well-known-parameter-token");
3058                 return offset;
3059         }
3060
3061         switch (value) {
3062
3063         case 0x01:      /* Charset */
3064                 offset = add_parameter_charset (tree, value_buff, startOffset, offset);
3065                 break;
3066
3067         case 0x03:      /* Type */
3068                 offset = add_parameter_type (tree, value_buff, startOffset, offset);
3069                 break;
3070
3071         case 0x05:      /* Name */
3072                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3073                                     hf_wsp_parameter_name, "Name");
3074                 break;
3075
3076         case 0x06:      /* Filename */
3077                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3078                                     hf_wsp_parameter_filename, "Filename");
3079                 break;
3080
3081         case 0x09:      /* Type (special) */
3082                 offset = add_constrained_encoding(tree, value_buff, startOffset, offset);
3083                 break;
3084
3085         case 0x0A:      /* Start */
3086                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3087                                     hf_wsp_parameter_start, "Start");
3088                 break;
3089
3090         case 0x0B:      /* Start-info */
3091                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3092                                     hf_wsp_parameter_start_info, "Start-info");
3093                 break;
3094
3095         case 0x0C:      /* Comment */
3096                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3097                                     hf_wsp_parameter_comment, "Comment");
3098                 break;
3099
3100         case 0x0D:      /* Domain */
3101                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3102                                     hf_wsp_parameter_domain, "Domain");
3103                 break;
3104
3105         case 0x0F:      /* Path */
3106                 offset = add_parameter_text (tree, value_buff, startOffset, offset,
3107                                     hf_wsp_parameter_path, "Path");
3108                 break;
3109
3110         case 0x00:      /* Q */
3111         case 0x02:      /* Level */
3112         case 0x07:      /* Differences */
3113         case 0x08:      /* Padding */
3114         case 0x0E:      /* Max-Age */
3115         case 0x10:      /* Secure */
3116         default:
3117                 break;
3118         }
3119
3120         return offset;
3121 }
3122
3123 static int
3124 add_untyped_parameter (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3125     int offset)
3126 {
3127         const guint8 *token;
3128         value_type_t valueType;
3129         int subvalueLen;
3130         int subvalueOffset;
3131         guint value;
3132         int vOffset = offset;
3133
3134         token = tvb_get_ptr (value_buff, startOffset, offset - startOffset);
3135         /*
3136          * Now an Untyped-value; either an Integer-value or a Text-value.
3137          */
3138         valueType = get_value_type_len (value_buff, offset,
3139             &subvalueLen, &subvalueOffset, &offset);
3140         if (valueType == VALUE_IS_TEXT_STRING)
3141         {
3142                 /*
3143                  * Text-value.
3144                  */
3145                 if ((offset - vOffset) == 1) {
3146                         /*
3147                          * No-value.  (stringSize includes the terminating
3148                          * null byte, so an empty string has a size of 1.)
3149                          */
3150                         proto_tree_add_text (tree, value_buff, startOffset,
3151                             offset - startOffset,
3152                             "%s", token);
3153                         return offset;
3154                 }
3155                 proto_tree_add_text (tree, value_buff, startOffset,
3156                     offset - startOffset,
3157                     "%s: %s", token,
3158                     tvb_get_ptr (value_buff, vOffset, offset - vOffset));
3159         }
3160         else
3161         {
3162                 /*
3163                  * Integer-value.
3164                  */
3165                 if (get_integer (value_buff, subvalueOffset, subvalueLen,
3166                     valueType, &value) == 0)
3167                 {
3168                         proto_tree_add_text (tree, value_buff, startOffset,
3169                             offset - startOffset,
3170                             "%s: %u", token, value);
3171                 }
3172                 else
3173                 {
3174                         proto_tree_add_text (tree, value_buff, startOffset,
3175                             offset - startOffset,
3176                             "%s: Invalid Integer-value", token);
3177                 }
3178         }
3179         return offset;
3180 }
3181
3182 static int
3183 add_parameter_charset (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3184     int offset)
3185 {
3186         value_type_t valueType;
3187         int subvalueLen;
3188         int subvalueOffset;
3189         guint value;
3190
3191         valueType = get_value_type_len (value_buff, offset,
3192             &subvalueLen, &subvalueOffset, &offset);
3193         if (valueType == VALUE_IN_LEN)
3194         {
3195                 /*
3196                  * Integer-value.
3197                  */
3198                 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset,
3199                     value_buff, startOffset, offset - startOffset,
3200                     subvalueLen);       /* subvalueLen is the value */
3201                 return offset;
3202         }
3203         if (valueType == VALUE_IS_TEXT_STRING)
3204         {
3205                 /*
3206                  * Invalid.
3207                  */
3208                 proto_tree_add_text (tree, value_buff, startOffset,
3209                     offset - startOffset, "Invalid Well-known charset");
3210                 return offset;
3211         }
3212
3213         /*
3214          * First byte had the 8th bit set.
3215          */
3216         if (subvalueLen == 0) {
3217                 /*
3218                  * Any-charset.
3219                  * XXX - add this as a field?
3220                  */
3221                 proto_tree_add_text (tree, value_buff, startOffset,
3222                     offset- startOffset, "*");
3223                 return offset;
3224         }
3225
3226         if (get_integer(value_buff, subvalueOffset, subvalueLen,
3227             valueType, &value) == -1) {
3228                 proto_tree_add_text (tree, value_buff, startOffset,
3229                     offset - startOffset, "Length %u not handled in Well-known charset",
3230                         subvalueLen);
3231         } else {
3232                 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset,
3233                     value_buff, startOffset, offset - startOffset, value);
3234         }
3235         return offset;
3236 }
3237
3238 static int
3239 add_constrained_encoding (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3240     int offset)
3241 {
3242         value_type_t valueType;
3243         int subvalueLen;
3244         int subvalueOffset;
3245         guint value;
3246
3247         valueType = get_value_type_len (value_buff, offset,
3248             &subvalueLen, &subvalueOffset, &offset);
3249         if (valueType == VALUE_IN_LEN)
3250         {
3251                 /*
3252                  * Integer-value, invalid
3253                  */
3254                 proto_tree_add_text (tree, value_buff, startOffset,
3255                     offset - startOffset, "Invalid multipart type parameter");
3256                 return offset;
3257         }
3258         if (valueType == VALUE_IS_TEXT_STRING)
3259         {
3260                 /*
3261                  * type-label.
3262                  */
3263                 proto_tree_add_string (tree, hf_wsp_parameter_upart_type,
3264                     value_buff, startOffset, offset - startOffset,
3265                     tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
3266                 return offset;
3267         }
3268         /*
3269          * First byte had the 8th bit set.
3270          */
3271         get_integer(value_buff, subvalueOffset, subvalueLen, valueType, &value);
3272         proto_tree_add_uint (tree, hf_wsp_parameter_upart_type_value,
3273             value_buff, startOffset, offset - startOffset, value);
3274         return offset;
3275 }
3276
3277 static int
3278 add_parameter_type (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3279     int offset)
3280 {
3281         value_type_t valueType;
3282         int subvalueLen;
3283         int subvalueOffset;
3284         guint value;
3285
3286         valueType = get_value_type_len (value_buff, offset,
3287             &subvalueLen, &subvalueOffset, &offset);
3288         if (get_integer(value_buff, subvalueOffset, subvalueLen,
3289             valueType, &value) == -1) {
3290                 proto_tree_add_text (tree, value_buff, startOffset,
3291                     offset - startOffset, "Invalid type");
3292         } else {
3293                 proto_tree_add_uint (tree, hf_wsp_parameter_type, value_buff,
3294                     startOffset, offset - startOffset, value);
3295         }
3296         return offset;
3297 }
3298
3299 static int
3300 add_parameter_text (proto_tree *tree, tvbuff_t *value_buff, int startOffset,
3301     int offset, int hf_string, const char *paramName)
3302 {
3303         value_type_t valueType;
3304         int subvalueLen;
3305         int subvalueOffset;
3306
3307         valueType = get_value_type_len (value_buff, offset,
3308             &subvalueLen, &subvalueOffset, &offset);
3309         if (valueType != VALUE_IS_TEXT_STRING) {
3310                 proto_tree_add_text (tree, value_buff, startOffset,
3311                     offset - startOffset, "Invalid %s", paramName);
3312         } else {
3313                 proto_tree_add_string (tree, hf_string, value_buff,
3314                             startOffset, offset - startOffset,
3315                             tvb_get_ptr (value_buff, subvalueOffset, subvalueLen));
3316         }
3317         return offset;
3318 }
3319
3320 static void
3321 add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType,
3322     const char *contentTypeStr)
3323 {
3324         guint offset = 0;
3325         guint variableStart = 0;
3326         guint variableEnd = 0;
3327         guint valueStart = 0;
3328         guint valueEnd = 0;
3329         guint8 peek = 0;
3330         proto_item *ti;
3331         
3332         /* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_length_remaining(tvb, offset),bo_little_endian); */
3333         ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_reported_length(tvb),bo_little_endian);
3334
3335         if (contentTypeStr == NULL && contentType == 0x12)
3336         {
3337                 /*
3338                  * URL Encoded data.
3339                  * Iterate through post data.
3340                  */
3341                 for (offset = 0; offset < tvb_reported_length (tvb); offset++)
3342                 {
3343                         peek = tvb_get_guint8 (tvb, offset);
3344                         if (peek == '=')
3345                         {
3346                                 variableEnd = offset;
3347                                 valueStart = offset+1;
3348                         }
3349                         else if (peek == '&')
3350                         {
3351                                 if (variableEnd > 0)
3352                                 {
3353                                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
3354                                 }
3355                                 variableStart = offset+1;
3356                                 variableEnd = 0;
3357                                 valueStart = 0;
3358                                 valueEnd = 0;
3359                         }
3360                 }
3361
3362                 /* See if there's outstanding data */
3363                 if (variableEnd > 0)
3364                 {
3365                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
3366                 }
3367         }
3368         else if ((contentType == 0x22) || (contentType == 0x23) || (contentType == 0x23) || (contentType == 0x24) ||
3369                  (contentType == 0x25) || (contentType == 0x26) || (contentType == 0x33))
3370         {
3371                 add_multipart_data(ti, tvb);
3372         }
3373 }
3374
3375 static void
3376 add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
3377 {
3378         int variableLength = variableEnd-variableStart;
3379         int valueLength = 0;
3380         char *variableBuffer;
3381         char *valueBuffer;
3382
3383         variableBuffer = g_malloc (variableLength+1);
3384         strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength);
3385         variableBuffer[variableLength] = 0;
3386
3387         if (valueEnd < valueStart)
3388         {
3389                 valueBuffer = g_malloc (1);
3390                 valueBuffer[0] = 0;
3391                 valueEnd = valueStart;
3392         }
3393         else
3394         {
3395                 valueLength = valueEnd-valueStart;
3396                 valueBuffer = g_malloc (valueLength+1);
3397                 strncpy (valueBuffer, tvb_get_ptr (tvb, valueStart, valueLength), valueLength);
3398                 valueBuffer[valueLength] = 0;
3399         }
3400
3401         /* Check for variables with no value */
3402         if (valueStart >= tvb_reported_length (tvb))
3403         {
3404                 valueStart = tvb_reported_length (tvb);
3405                 valueEnd = valueStart;
3406         }
3407         valueLength = valueEnd-valueStart;
3408
3409         proto_tree_add_text (tree, tvb, variableStart, valueEnd-variableStart, "%s: %s", variableBuffer, valueBuffer);
3410
3411         g_free (variableBuffer);
3412         g_free (valueBuffer);
3413 }
3414
3415 void
3416 add_multipart_data (proto_tree *tree, tvbuff_t *tvb)
3417 {
3418         int              offset = 0;
3419         guint            nextOffset;
3420         guint            nEntries = 0;
3421         guint            count;
3422         guint            HeadersLen;
3423         guint            DataLen;
3424         guint            contentType = 0;
3425         const char      *contentTypeStr;
3426         tvbuff_t        *tmp_tvb;
3427         int              partnr = 1;
3428         int              part_start;
3429
3430         proto_item      *sub_tree = NULL,
3431                         *ti;
3432         proto_tree      *mpart_tree;
3433
3434         nEntries = tvb_get_guintvar (tvb, offset, &count);
3435         offset += count;
3436         if (nEntries)
3437         {
3438                 sub_tree = proto_tree_add_text(tree, tvb, offset - count, 0,
3439                                         "Multipart body");
3440                 proto_item_add_subtree(sub_tree, ett_mpartlist);
3441         }
3442         while (nEntries--)
3443         {
3444                 part_start = offset;
3445                 HeadersLen = tvb_get_guintvar (tvb, offset, &count);
3446                 offset += count;
3447                 DataLen = tvb_get_guintvar (tvb, offset, &count);
3448                 offset += count;
3449                 ti = proto_tree_add_uint(sub_tree, hf_wsp_mpart, tvb, part_start,
3450                                         HeadersLen + DataLen + (offset - part_start), partnr);
3451                 mpart_tree = proto_item_add_subtree(ti, ett_multiparts);
3452                 nextOffset = add_content_type (mpart_tree, tvb, offset, &contentType, &contentTypeStr);
3453                 HeadersLen -= (nextOffset - offset);
3454                 if (HeadersLen > 0)
3455                 {
3456                         tmp_tvb = tvb_new_subset (tvb, nextOffset, HeadersLen, HeadersLen);
3457                         add_headers (mpart_tree, tmp_tvb);
3458                 }
3459                 offset = nextOffset + HeadersLen;
3460                 proto_tree_add_item (mpart_tree, hf_wsp_multipart_data, tvb, offset, DataLen, bo_little_endian);
3461                 offset += DataLen;
3462                 partnr++;
3463         }
3464 }
3465
3466 static gint
3467 get_integer (tvbuff_t *tvb, guint offset, guint valueLength,
3468     value_type_t valueType, guint *value)
3469 {
3470         if (valueType == VALUE_IS_TEXT_STRING) {
3471                 /*
3472                  * Not valid.
3473                  */
3474                 return -1;
3475         }
3476
3477         if (valueType == VALUE_IN_LEN) {
3478                 /*
3479                  * Short-integer.
3480                  */
3481                 *value = valueLength;
3482                 return 0;
3483         }
3484
3485         /*
3486          * Long-integer.
3487          */
3488         switch (valueLength)
3489         {
3490                 case 1:
3491                         *value = tvb_get_guint8(tvb, offset);
3492                         break;
3493                 case 2:
3494                         *value = tvb_get_ntohs(tvb, offset);
3495                         break;
3496                 case 3:
3497                         *value = tvb_get_ntoh24(tvb, offset);
3498                         break;
3499                 case 4:
3500                         *value = tvb_get_ntohl(tvb, offset);
3501                         break;
3502                 default:
3503                         /* TODO: Need to read peek octets */
3504                         *value = 0;
3505                         fprintf (stderr, "dissect_wsp: get_integer size %u NYI\n", valueLength);
3506                         break;
3507         }
3508         return 0;
3509 }
3510
3511 /* Register the protocol with Ethereal */
3512 void
3513 proto_register_wsp(void)
3514 {                 
3515
3516 /* Setup list of header fields */
3517         static hf_register_info hf[] = {
3518                 { &hf_wsp_header_tid,
3519                         {       "Transmission ID",           
3520                                 "wsp.TID",
3521                                  FT_UINT8, BASE_HEX, NULL, 0x00,
3522                                 "Transmission ID", HFILL
3523                         }
3524                 },
3525                 { &hf_wsp_header_pdu_type,
3526                         {       "PDU Type",           
3527                                 "wsp.pdu_type",
3528                                  FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
3529                                 "PDU Type", HFILL
3530                         }
3531                 },
3532                 { &hf_wsp_version_major,
3533                         {       "Version (Major)",           
3534                                 "wsp.version.major",
3535                                  FT_UINT8, BASE_DEC, NULL, 0xF0,
3536                                 "Version (Major)", HFILL
3537                         }
3538                 },
3539                 { &hf_wsp_version_minor,
3540                         {       "Version (Minor)",           
3541                                 "wsp.version.minor",
3542                                  FT_UINT8, BASE_DEC, NULL, 0x0F,
3543                                 "Version (Minor)", HFILL
3544                         }
3545                 },
3546                 { &hf_wsp_capability_length,
3547                         {       "Capability Length",           
3548                                 "wsp.capability.length",
3549                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3550                                 "Capability Length", HFILL
3551                         }
3552                 },
3553                 { &hf_wsp_header_length,
3554                         {       "Headers Length",           
3555                                 "wsp.headers_length",
3556                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3557                                 "Headers Length", HFILL
3558                         }
3559                 },
3560                 { &hf_wsp_capabilities_section,
3561                         {       "Capabilities",           
3562                                 "wsp.capabilities",
3563                                  FT_NONE, BASE_DEC, NULL, 0x00,
3564                                 "Capabilities", HFILL
3565                         }
3566                 },
3567                 { &hf_wsp_headers_section,
3568                         {       "Headers",           
3569                                 "wsp.headers",
3570                                  FT_NONE, BASE_DEC, NULL, 0x00,
3571                                 "Headers", HFILL
3572                         }
3573                 },
3574                 { &hf_wsp_header,
3575                         {       "Header",           
3576                                 "wsp.headers.header",
3577                                  FT_NONE, BASE_DEC, NULL, 0x00,
3578                                 "Header", HFILL
3579                         }
3580                 },
3581                 { &hf_wsp_header_uri_len,
3582                         {       "URI Length",           
3583                                 "wsp.uri_length",
3584                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3585                                 "URI Length", HFILL
3586                         }
3587                 },
3588                 { &hf_wsp_header_uri,
3589                         {       "URI",           
3590                                 "wsp.uri",
3591                                  FT_STRING, BASE_NONE, NULL, 0x00,
3592                                 "URI", HFILL
3593                         }
3594                 },
3595                 { &hf_wsp_server_session_id,
3596                         {       "Server Session ID",           
3597                                 "wsp.server.session_id",
3598                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3599                                 "Server Session ID", HFILL
3600                         }
3601                 },
3602                 { &hf_wsp_header_status,
3603                         {       "Status",           
3604                                 "wsp.reply.status",
3605                                  FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
3606                                 "Status", HFILL
3607                         }
3608                 },
3609                 { &hf_wsp_content_type,
3610                         {       "Content Type",           
3611                                 "wsp.content_type.type",
3612                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
3613                                 "Content Type", HFILL
3614                         }
3615                 },
3616                 { &hf_wsp_content_type_str,
3617                         {       "Content Type",           
3618                                 "wsp.content_type.type.string",
3619                                  FT_STRING, BASE_NONE, NULL, 0x00,
3620                                 "Content Type", HFILL
3621                         }
3622                 },
3623                 { &hf_wsp_parameter_well_known_charset,
3624                         {       "Charset",           
3625                                 "wsp.content_type.parameter.charset",
3626                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
3627                                 "Charset", HFILL
3628                         }
3629                 },
3630                 { &hf_wsp_parameter_type,
3631                         {       "Type",           
3632                                 "wsp.content_type.parameter.type",
3633                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3634                                 "Type", HFILL
3635                         }
3636                 },
3637                 { &hf_wsp_parameter_name,
3638                         {       "Name",
3639                                 "wsp.content_type.parameter.name",
3640                                  FT_STRING, BASE_NONE, NULL, 0x00,
3641                                 "Name", HFILL
3642                         }
3643                 },
3644                 { &hf_wsp_parameter_filename,
3645                         {       "Filename",
3646                                 "wsp.content_type.parameter.filename",
3647                                  FT_STRING, BASE_NONE, NULL, 0x00,
3648                                 "Filename", HFILL
3649                         }
3650                 },
3651                 { &hf_wsp_parameter_start,
3652                         {       "Start",
3653                                 "wsp.content_type.parameter.start",
3654                                  FT_STRING, BASE_NONE, NULL, 0x00,
3655                                 "Start", HFILL
3656                         }
3657                 },
3658                 { &hf_wsp_parameter_start_info,
3659                         {       "Start-info",
3660                                 "wsp.content_type.parameter.start_info",
3661                                  FT_STRING, BASE_NONE, NULL, 0x00,
3662                                 "Start-info", HFILL
3663                         }
3664                 },
3665                 { &hf_wsp_parameter_comment,
3666                         {       "Comment",
3667                                 "wsp.content_type.parameter.comment",
3668                                  FT_STRING, BASE_NONE, NULL, 0x00,
3669                                 "Comment", HFILL
3670                         }
3671                 },
3672                 { &hf_wsp_parameter_domain,
3673                         {       "Domain",
3674                                 "wsp.content_type.parameter.domain",
3675                                  FT_STRING, BASE_NONE, NULL, 0x00,
3676                                 "Domain", HFILL
3677                         }
3678                 },
3679                 { &hf_wsp_parameter_path,
3680                         {       "Path",
3681                                 "wsp.content_type.parameter.path",
3682                                  FT_STRING, BASE_NONE, NULL, 0x00,
3683                                 "Path", HFILL
3684                         }
3685                 },
3686                 { &hf_wsp_parameter_upart_type,
3687                         {       "Type",
3688                                 "wsp.content_type.parameter.upart.type",
3689                                  FT_STRING, BASE_NONE, NULL, 0x00,
3690                                 "Multipart type", HFILL
3691                         }
3692                 },
3693                 { &hf_wsp_parameter_upart_type_value,
3694                         {       "Type",
3695                                 "wsp.content_type.parameter.upart.type.int",
3696                                  FT_UINT8, BASE_DEC, NULL, 0x00,
3697                                 "Multipart type (int value)", HFILL
3698                         }
3699                 },
3700                 { &hf_wsp_reply_data,
3701                         {       "Data",           
3702                                 "wsp.reply.data",
3703                                  FT_NONE, BASE_NONE, NULL, 0x00,
3704                                 "Data", HFILL
3705                         }
3706                 },
3707                 { &hf_wsp_header_shift_code,
3708                         {       "Shift code",           
3709                                 "wsp.header.shift",
3710                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3711                                  FT_UINT8, BASE_HEX, NULL, 0x00,
3712                                 "Shift code", HFILL
3713                         }
3714                 },
3715                 { &hf_wsp_header_accept,
3716                         {       "Accept",           
3717                                 "wsp.header.accept",
3718                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3719                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
3720                                 "Accept", HFILL
3721                         }
3722                 },
3723                 { &hf_wsp_header_accept_str,
3724                         {       "Accept",           
3725                                 "wsp.header.accept.string",
3726                                  FT_STRING, BASE_NONE, NULL, 0x00,
3727                                 "Accept", HFILL
3728                         }
3729                 },
3730                 { &hf_wsp_header_accept_application,
3731                         {       "Accept-Application",           
3732                                 "wsp.header.accept_application",
3733                                  FT_UINT32, BASE_HEX, NULL, 0x00,
3734                                 "Accept-Application", HFILL
3735                         }
3736                 },
3737                 { &hf_wsp_header_accept_application_str,
3738                         {       "Accept-Application",
3739                                 "wsp.header.accept_application.string",
3740                                  FT_STRING, BASE_NONE, NULL, 0x00,
3741                                 "Accept-Application", HFILL
3742                         }
3743                 },
3744                 { &hf_wsp_header_accept_charset,
3745                         {       "Accept-Charset",           
3746                                 "wsp.header.accept_charset",
3747                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
3748                                 "Accept-Charset", HFILL
3749                         }
3750                 },
3751                 { &hf_wsp_header_accept_charset_str,
3752                         {       "Accept-Charset",           
3753                                 "wsp.header.accept_charset.string",
3754                                  FT_STRING, BASE_NONE, NULL, 0x00,
3755                                 "Accept-Charset", HFILL
3756                         }
3757                 },
3758                 { &hf_wsp_header_accept_language,
3759                         {       "Accept-Language",           
3760                                 "wsp.header.accept_language",
3761                                  FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
3762                                 "Accept-Language", HFILL
3763                         }
3764                 },
3765                 { &hf_wsp_header_accept_language_str,
3766                         {       "Accept-Language",           
3767                                 "wsp.header.accept_language.string",
3768                                  FT_STRING, BASE_NONE, NULL, 0x00,
3769                                 "Accept-Language", HFILL
3770                         }
3771                 },
3772                 { &hf_wsp_header_accept_ranges,
3773                         {       "Accept-Ranges",           
3774                                 "wsp.header.accept_ranges",
3775                                  FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
3776                                 "Accept-Ranges", HFILL
3777                         }
3778                 },
3779                 { &hf_wsp_header_accept_ranges_str,
3780                         {       "Accept-Ranges",           
3781                                 "wsp.header.accept_ranges.string",
3782                                  FT_STRING, BASE_NONE, NULL, 0x00,
3783                                 "Accept-Ranges", HFILL
3784                         }
3785                 },
3786                 { &hf_wsp_header_age,
3787                         {       "Age",           
3788                                 "wsp.header.age",
3789                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3790                                 "Age", HFILL
3791                         }
3792                 },
3793                 { &hf_wsp_header_bearer_indication,
3794                         /*
3795                          * XXX - I'm assuming that the bearer indication is
3796                          * just a bearer type.
3797                          */
3798                         {       "Bearer-indication",           
3799                                 "wsp.header.bearer_indication",
3800                                  FT_UINT32, BASE_HEX, VALS(vals_bearer_types), 0x00,
3801                                 "Bearer-indication", HFILL
3802                         }
3803                 },
3804                 { &hf_wsp_header_cache_control,
3805                         {       "Cache-Control",           
3806                                 "wsp.header.cache_control",
3807                                  FT_UINT8, BASE_HEX, VALS ( vals_cache_control ), 0x00,
3808                                 "Cache-Control", HFILL
3809                         }
3810                 },
3811                 { &hf_wsp_header_cache_control_str,
3812                         {       "Cache-Control",           
3813                                 "wsp.header.cache_control.string",
3814                                  FT_STRING, BASE_NONE, NULL, 0x00,
3815                                 "Cache-Control", HFILL
3816                         }
3817                 },
3818                 { &hf_wsp_header_cache_control_field_name,
3819                         {       "Field Name",
3820                                 "wsp.header.cache_control.field_name",
3821                                  FT_UINT8, BASE_HEX, VALS ( vals_field_names ), 0x00,
3822                                 "Cache-Control field name", HFILL
3823                         }
3824                 },
3825                 { &hf_wsp_header_cache_control_field_name_str,
3826                         {       "Field Name",
3827                                 "wsp.header.cache_control.field_name.str",
3828                                  FT_STRING, BASE_NONE, NULL, 0x00,
3829                                 "Cache-Control field name", HFILL
3830                         }
3831                 },
3832                 { &hf_wsp_header_connection,
3833                         {       "Connection",           
3834                                 "wsp.header.connection",
3835                                  FT_UINT8, BASE_HEX, VALS ( vals_connection ), 0x00,
3836                                 "Connection", HFILL
3837                         }
3838                 },
3839                 { &hf_wsp_header_connection_str,
3840                         {       "Connection",           
3841                                 "wsp.header.connection_str",
3842                                  FT_STRING, BASE_NONE, NULL, 0x00,
3843                                 "Connection", HFILL
3844                         }
3845                 },
3846                 { &hf_wsp_header_content_length,
3847                         {       "Content-Length",           
3848                                 "wsp.header.content_length",
3849                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3850                                 "Content-Length", HFILL
3851                         }
3852                 },
3853                 { &hf_wsp_header_date,
3854                         {       "Date",           
3855                                 "wsp.header.date",
3856                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
3857                                 "Date", HFILL
3858                         }
3859                 },
3860                 { &hf_wsp_header_etag,
3861                         {       "Etag",           
3862                                 "wsp.header.etag",
3863                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3864                                  FT_STRING, BASE_NONE, NULL, 0x00,
3865                                 "Etag", HFILL
3866                         }
3867                 },
3868                 { &hf_wsp_header_expires,
3869                         {       "Expires",           
3870                                 "wsp.header.expires",
3871                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
3872                                 "Expires", HFILL
3873                         }
3874                 },
3875                 { &hf_wsp_header_last_modified,
3876                         {       "Last-Modified",           
3877                                 "wsp.header.last_modified",
3878                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
3879                                 "Last-Modified", HFILL
3880                         }
3881                 },
3882                 { &hf_wsp_header_location,
3883                         {       "Location",           
3884                                 "wsp.header.location",
3885                                  FT_STRING, BASE_NONE, NULL, 0x00,
3886                                 "Location", HFILL
3887                         }
3888                 },
3889                 { &hf_wsp_header_if_modified_since,
3890                         {       "If-Modified-Since",           
3891                                 "wsp.header.if_modified_since",
3892                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
3893                                 "If-Modified-Since", HFILL
3894                         }
3895                 },
3896                 { &hf_wsp_header_pragma,
3897                         {       "Pragma",           
3898                                 "wsp.header.pragma",
3899                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3900                                  FT_STRING, BASE_NONE, NULL, 0x00,
3901                                 "pragma", HFILL
3902                         }
3903                 },
3904                 { &hf_wsp_header_profile,
3905                         {       "Profile",           
3906                                 "wsp.header.profile",
3907                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3908                                  FT_STRING, BASE_NONE, NULL, 0x00,
3909                                 "Profile", HFILL
3910                         }
3911                 },
3912                 { &hf_wsp_header_server,
3913                         {       "Server",           
3914                                 "wsp.header.server",
3915                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3916                                  FT_STRING, BASE_NONE, NULL, 0x00,
3917                                 "Server", HFILL
3918                         }
3919                 },
3920                 { &hf_wsp_header_transfer_encoding,
3921                         {       "Transfer Encoding",           
3922                                 "wsp.header.transfer_enc",
3923                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3924                                  FT_UINT8, BASE_HEX, VALS ( vals_transfer_encoding ), 0x00,
3925                                 "Transfer Encoding", HFILL
3926                         }
3927                 },
3928                 { &hf_wsp_header_transfer_encoding_str,
3929                         {       "Transfer Encoding",           
3930                                 "wsp.header.transfer_enc_str",
3931                                  FT_STRING, BASE_NONE, NULL, 0x00,
3932                                 "Transfer Encoding", HFILL
3933                         }
3934                 },
3935                 { &hf_wsp_header_user_agent,
3936                         {       "User-Agent",           
3937                                 "wsp.header.user_agent",
3938                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
3939                                  FT_STRING, BASE_NONE, NULL, 0x00,
3940                                 "User-Agent", HFILL
3941                         }
3942                 },
3943                 { &hf_wsp_header_via,
3944                         {       "Via",           
3945                                 "wsp.header.via",
3946                                  FT_STRING, BASE_NONE, NULL, 0x00,
3947                                 "Via", HFILL
3948                         }
3949                 },
3950                 { &hf_wsp_header_wap_application_id,
3951                         {       "X-Wap-Application-Id",           
3952                                 "wsp.header.wap_application_id",
3953                                  FT_UINT8, BASE_HEX, NULL, 0x00,
3954                                 "WAP application id", HFILL
3955                         }
3956                 },
3957                 { &hf_wsp_header_wap_application_id_str,
3958                         {       "X-Wap-Application-Id",           
3959                                 "wsp.header.wap_application_id.string",
3960                                  FT_STRING, BASE_NONE, NULL, 0x00,
3961                                 "WAP application id", HFILL
3962                         }
3963                 },
3964                 { &hf_wsp_header_warning,
3965                         {       "Warning",
3966                                 "wsp.header.warning",
3967                                  FT_NONE, BASE_NONE, NULL, 0x00,
3968                                 "Warning", HFILL
3969                         }
3970                 },
3971                 { &hf_wsp_header_warning_code,
3972                         {       "Warning Code",
3973                                 "wsp.header.warning.code",
3974                                  FT_UINT32, BASE_DEC, NULL, 0x00,
3975                                 "Warning Code", HFILL
3976                         }
3977                 },
3978                 { &hf_wsp_header_warning_agent,
3979                         {       "Warning Agent",
3980                                 "wsp.header.warning.agent",
3981                                  FT_STRING, BASE_NONE, NULL, 0x00,
3982                                 "Warning Agent", HFILL
3983                         }
3984                 },
3985                 { &hf_wsp_header_warning_text,
3986                         {       "Warning Text",
3987                                 "wsp.header.warning.text",
3988                                  FT_STRING, BASE_NONE, NULL, 0x00,
3989                                 "Warning Text", HFILL
3990                         }
3991                 },
3992                 { &hf_wsp_header_application_header,
3993                         {       "Application Header",           
3994                                 "wsp.header.application_header",
3995                                  FT_STRING, BASE_NONE, NULL, 0x00,
3996                                 "Application Header", HFILL
3997                         }
3998                 },
3999                 { &hf_wsp_header_application_value,
4000                         {       "Application Header Value",           
4001                                 "wsp.header.application_header.value",
4002                                  FT_STRING, BASE_NONE, NULL, 0x00,
4003                                 "Application Header Value", HFILL
4004                         }
4005                 },
4006                 { &hf_wsp_header_content_ID,
4007                         {       "Content-ID",           
4008                                 "wsp.header.content-id",
4009                                  FT_STRING, BASE_NONE, NULL, 0x00,
4010                                 "Content-ID", HFILL
4011                         }
4012                 },
4013                 { &hf_wsp_header_x_wap_tod,
4014                         {       "X-WAP.TOD",           
4015                                 "wsp.header.x_wap_tod",
4016                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
4017                                 "X-WAP.TOD", HFILL
4018                         }
4019                 },
4020                 { &hf_wsp_capabilities_client_SDU,
4021                         {       "Client SDU",
4022                                 "wsp.capabilities.client_SDU",
4023                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4024                                 "Client SDU", HFILL
4025                         }
4026                 },
4027                 { &hf_wsp_capabilities_server_SDU,
4028                         {       "Server SDU",
4029                                 "wsp.capabilities.server_SDU",
4030                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4031                                 "Server SDU", HFILL
4032                         }
4033                 },
4034                 { &hf_wsp_capabilities_protocol_opt,
4035                         {       "Protocol Options",
4036                                 "wsp.capabilities.protocol_opt",
4037                                  FT_STRING, BASE_HEX, NULL, 0x00,
4038                                 "Protocol Options", HFILL
4039                         }
4040                 },
4041                 { &hf_wsp_capabilities_method_MOR,
4042                         {       "Method MOR",
4043                                 "wsp.capabilities.method_mor",
4044                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4045                                 "Method MOR", HFILL
4046                         }
4047                 },
4048                 { &hf_wsp_capabilities_push_MOR,
4049                         {       "Push MOR",
4050                                 "wsp.capabilities.push_mor",
4051                                  FT_UINT8, BASE_DEC, NULL, 0x00,
4052                                 "Push MOR", HFILL
4053                         }
4054                 },
4055                 { &hf_wsp_capabilities_extended_methods,
4056                         {       "Extended Methods",
4057                                 "wsp.capabilities.extend_methods",
4058                                  FT_STRING, BASE_HEX, NULL, 0x00,
4059                                 "Extended Methods", HFILL
4060                         }
4061                 },
4062                 { &hf_wsp_capabilities_header_code_pages,
4063                         {       "Header Code Pages",
4064                                 "wsp.capabilities.code_pages",
4065                                  FT_STRING, BASE_HEX, NULL, 0x00,
4066                                 "Header Code Pages", HFILL
4067                         }
4068                 },
4069                 { &hf_wsp_capabilities_aliases,
4070                         {       "Aliases",
4071                                 "wsp.capabilities.aliases",
4072                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4073                                 "Aliases", HFILL
4074                         }
4075                 },
4076                 { &hf_wsp_post_data,
4077                         {       "Post Data",           
4078                                 "wsp.post.data",
4079                                  FT_NONE, BASE_NONE, NULL, 0x00,
4080                                 "Post Data", HFILL
4081                         }
4082                 },
4083                 { &hf_wsp_push_data,
4084                         {       "Push Data",           
4085                                 "wsp.push.data",
4086                                  FT_NONE, BASE_NONE, NULL, 0x00,
4087                                 "Push Data", HFILL
4088                         }
4089                 },
4090                 { &hf_wsp_multipart_data,
4091                         {       "Data in this part",           
4092                                 "wsp.multipart.data",
4093                                  FT_NONE, BASE_NONE, NULL, 0x00,
4094                                 "The data of 1 MIME-multipart part.", HFILL
4095                         }
4096                 },
4097                 { &hf_wsp_mpart,
4098                         {       "Part",           
4099                                 "wsp.multipart",
4100                                  FT_UINT32, BASE_DEC, NULL, 0x00,
4101                                 "MIME part of multipart data.", HFILL
4102                         }
4103                 },
4104                 { &hf_wsp_redirect_flags,
4105                         {       "Flags",
4106                                 "wsp.redirect_flags",
4107                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4108                                 "Redirect Flags", HFILL
4109                         }
4110                 },
4111                 { &hf_wsp_redirect_permanent,
4112                         {       "Permanent Redirect",
4113                                 "wsp.redirect_flags.permanent",
4114                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), PERMANENT_REDIRECT,
4115                                 "Permanent Redirect", HFILL
4116                         }
4117                 },
4118                 { &hf_wsp_redirect_reuse_security_session,
4119                         {       "Reuse Security Session",
4120                                 "wsp.redirect_flags.reuse_security_session",
4121                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), REUSE_SECURITY_SESSION,
4122                                 "Permanent Redirect", HFILL
4123                         }
4124                 },
4125                 { &hf_wsp_redirect_afl,
4126                         {       "Flags/Length",
4127                                 "wsp.redirect_afl",
4128                                  FT_UINT8, BASE_HEX, NULL, 0x00,
4129                                 "Redirect Address Flags/Length", HFILL
4130                         }
4131                 },
4132                 { &hf_wsp_redirect_afl_bearer_type_included,
4133                         {       "Bearer Type Included",
4134                                 "wsp.redirect_afl.bearer_type_included",
4135                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), BEARER_TYPE_INCLUDED,
4136                                 "Redirect Address bearer type included", HFILL
4137                         }
4138                 },
4139                 { &hf_wsp_redirect_afl_port_number_included,
4140                         {       "Port Number Included",
4141                                 "wsp.redirect_afl.port_number_included",
4142                                  FT_BOOLEAN, 8, TFS(&yes_no_truth), PORT_NUMBER_INCLUDED,
4143                                 "Redirect Address port number included", HFILL
4144                         }
4145                 },
4146                 { &hf_wsp_redirect_afl_address_len,
4147                         {       "Address Len",
4148                                 "wsp.redirect_afl.address_len",
4149                                  FT_UINT8, BASE_DEC, NULL, ADDRESS_LEN,
4150                                 "Redirect Address Length", HFILL
4151                         }
4152                 },
4153                 { &hf_wsp_redirect_bearer_type,
4154                         {       "Bearer Type",
4155                                 "wsp.redirect_bearer_type",
4156                                  FT_UINT8, BASE_HEX, VALS(vals_bearer_types), 0x0,
4157                                 "Redirect Bearer Type", HFILL
4158                         }
4159                 },
4160                 { &hf_wsp_redirect_port_num,
4161                         {       "Port Number",
4162                                 "wsp.redirect_port_num",
4163                                  FT_UINT16, BASE_DEC, NULL, 0x0,
4164                                 "Redirect Port Number", HFILL
4165                         }
4166                 },
4167                 { &hf_wsp_redirect_ipv4_addr,
4168                         {       "IP Address",
4169                                 "wsp.redirect_ipv4_addr",
4170                                  FT_IPv4, BASE_NONE, NULL, 0x0,
4171                                 "Redirect Address (IP)", HFILL
4172                         }
4173                 },
4174                 { &hf_wsp_redirect_ipv6_addr,
4175                         {       "IPv6 Address",
4176                                 "wsp.redirect_ipv6_addr",
4177                                  FT_IPv6, BASE_NONE, NULL, 0x0,
4178                                 "Redirect Address (IPv6)", HFILL
4179                         }
4180                 },
4181                 { &hf_wsp_redirect_addr,
4182                         {       "Address",
4183                                 "wsp.redirect_addr",
4184                                  FT_BYTES, BASE_NONE, NULL, 0x0,
4185                                 "Redirect Address", HFILL
4186                         }
4187                 },
4188         };
4189         
4190 /* Setup protocol subtree array */
4191         static gint *ett[] = {
4192                 &ett_wsp,
4193                 &ett_content_type_parameters,
4194                 &ett_header,
4195                 &ett_headers,
4196                 &ett_header_warning,
4197                 &ett_header_cache_control_parameters,
4198                 &ett_header_cache_control_field_names,
4199                 &ett_capabilities,
4200                 &ett_content_type,
4201                 &ett_redirect_flags,
4202                 &ett_redirect_afl,
4203                 &ett_multiparts,
4204                 &ett_mpartlist
4205         };
4206
4207 /* Register the protocol name and description */
4208         proto_wsp = proto_register_protocol(
4209                 "Wireless Session Protocol",    /* protocol name for use by ethereal */ 
4210                 "WSP",                          /* short version of name */
4211                 "wap-wsp"                       /* Abbreviated protocol name, should Match IANA 
4212                                                     < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
4213                                                   */
4214         );
4215
4216 /* Required function calls to register the header fields and subtrees used  */
4217         proto_register_field_array(proto_wsp, hf, array_length(hf));
4218         proto_register_subtree_array(ett, array_length(ett));
4219
4220         register_dissector("wsp-co", dissect_wsp_fromwap_co, proto_wsp);
4221         register_dissector("wsp-cl", dissect_wsp_fromwap_cl, proto_wsp);
4222         wsp_dissector_table = register_dissector_table("wsp.content_type.type",
4223             "WSP content type", FT_UINT8, BASE_HEX);
4224         register_heur_dissector_list("wsp", &heur_subdissector_list);
4225
4226         wsp_fromudp_handle = create_dissector_handle(dissect_wsp_fromudp,
4227             proto_wsp);
4228 };
4229
4230 void
4231 proto_reg_handoff_wsp(void)
4232 {
4233         /*
4234          * Get a handle for the WMLC dissector.
4235          */
4236         wmlc_handle = find_dissector("wmlc");   /* Coming soon :) */
4237
4238         /*
4239          * And get a handle for the WTP-over-UDP dissector.
4240          */
4241         wtp_fromudp_handle = find_dissector("wtp-udp");
4242
4243         /* Only connection-less WSP has no previous handler */
4244         dissector_add("udp.port", UDP_PORT_WSP, wsp_fromudp_handle);
4245         dissector_add("udp.port", UDP_PORT_WSP_PUSH, wsp_fromudp_handle);
4246
4247         /* This dissector is also called from the WTP and WTLS dissectors */
4248 }