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