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