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