Give the code that computes protocol statistics a progress dialog box,
[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.19 2001/02/19 21:02:33 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
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 "packet-wap.h"
58 #include "packet-wsp.h"
59
60 /* File scoped variables for the protocol and registered fields */
61 static int proto_wsp                                                    = HF_EMPTY;
62
63 /* These fields used by fixed part of header */
64 static int hf_wsp_header_tid                                    = HF_EMPTY;
65 static int hf_wsp_header_pdu_type                               = HF_EMPTY;
66 static int hf_wsp_version_major                                 = HF_EMPTY;
67 static int hf_wsp_version_minor                                 = HF_EMPTY;
68 static int hf_wsp_capability_length                             = HF_EMPTY;
69 static int hf_wsp_capabilities_section                  = HF_EMPTY;
70 static int hf_wsp_header_uri_len                                = HF_EMPTY;
71 static int hf_wsp_header_uri                                    = HF_EMPTY;
72 static int hf_wsp_server_session_id                             = HF_EMPTY;
73 static int hf_wsp_header_status                                 = HF_EMPTY;
74 static int hf_wsp_header_length                                 = HF_EMPTY;
75 static int hf_wsp_headers_section                               = HF_EMPTY;
76 static int hf_wsp_header                                                = HF_EMPTY;
77 static int hf_wsp_content_type                                  = HF_EMPTY;
78 static int hf_wsp_parameter_well_known_charset  = HF_EMPTY;
79 static int hf_wsp_reply_data                                    = HF_EMPTY;
80 static int hf_wsp_post_data                                             = HF_EMPTY;
81
82 static int hf_wsp_header_accept                                 = HF_EMPTY;
83 static int hf_wsp_header_accept_str                             = HF_EMPTY;
84 static int hf_wsp_header_accept_charset                 = HF_EMPTY;
85 static int hf_wsp_header_accept_charset_str             = HF_EMPTY;
86 static int hf_wsp_header_accept_language                = HF_EMPTY;
87 static int hf_wsp_header_accept_language_str    = HF_EMPTY;
88 static int hf_wsp_header_accept_ranges                  = HF_EMPTY;
89 static int hf_wsp_header_cache_control                  = HF_EMPTY;
90 static int hf_wsp_header_content_length                 = HF_EMPTY;
91 static int hf_wsp_header_age                                    = HF_EMPTY;
92 static int hf_wsp_header_date                                   = HF_EMPTY;
93 static int hf_wsp_header_etag                                   = HF_EMPTY;
94 static int hf_wsp_header_expires                                = HF_EMPTY;
95 static int hf_wsp_header_last_modified                  = HF_EMPTY;
96 static int hf_wsp_header_location                               = HF_EMPTY;
97 static int hf_wsp_header_if_modified_since              = HF_EMPTY;
98 static int hf_wsp_header_server                                 = HF_EMPTY;
99 static int hf_wsp_header_user_agent                             = HF_EMPTY;
100 static int hf_wsp_header_application_header             = HF_EMPTY;
101 static int hf_wsp_header_application_value              = HF_EMPTY;
102 static int hf_wsp_header_x_wap_tod                              = HF_EMPTY;
103 static int hf_wsp_header_transfer_encoding              = HF_EMPTY;
104 static int hf_wsp_header_transfer_encoding_str  = HF_EMPTY;
105 static int hf_wsp_header_via                                    = HF_EMPTY;
106
107 /* Initialize the subtree pointers */
108 static gint ett_wsp                                                     = ETT_EMPTY;
109 static gint ett_header                                                  = ETT_EMPTY;
110 static gint ett_headers                                                 = ETT_EMPTY;
111 static gint ett_capabilities                                    = ETT_EMPTY;
112 static gint ett_content_type                                    = ETT_EMPTY;
113
114 /* Handle for WMLC dissector */
115 static dissector_handle_t wmlc_handle;
116
117 static const value_string vals_pdu_type[] = {
118         { 0x00, "Reserved" },
119         { 0x01, "Connect" },
120         { 0x02, "ConnectReply" },
121         { 0x03, "Redirect" },
122         { 0x04, "Reply" },
123         { 0x05, "Disconnect" },
124         { 0x06, "Push" },
125         { 0x07, "ConfirmedPush" },
126         { 0x08, "Suspend" },
127         { 0x09, "Resume" },
128
129         /* 0x10 - 0x3F Unassigned */
130
131         { 0x40, "Get" },
132         { 0x41, "Options" },
133         { 0x42, "Head" },
134         { 0x43, "Delete" },
135         { 0x44, "Trace" },
136
137         /* 0x45 - 0x4F Unassigned (Get PDU) */
138         /* 0x50 - 0x5F Extended method (Get PDU) */
139
140         { 0x60, "Post" },
141         { 0x61, "Put" },
142
143         /* 0x62 - 0x6F Unassigned (Post PDU) */
144         /* 0x70 - 0x7F Extended method (Post PDU) */
145         /* 0x80 - 0xFF Reserved */
146
147         { 0x00, NULL }
148
149 };
150
151 static const value_string vals_status[] = {
152         /* 0x00 - 0x0F Reserved */
153
154         { 0x10, "Continue" },
155         { 0x11, "Switching Protocols" },
156
157         { 0x20, "OK" },
158         { 0x21, "Created" },
159         { 0x22, "Accepted" },
160         { 0x23, "Non-Authoritative Information" },
161         { 0x24, "No Content" },
162         { 0x25, "Reset Content" },
163         { 0x26, "Partial Content" },
164
165         { 0x30, "Multiple Choices" },
166         { 0x31, "Moved Permanently" },
167         { 0x32, "Moved Temporarily" },
168         { 0x33, "See Other" },
169         { 0x34, "Not Modified" },
170         { 0x35, "Use Proxy" },
171
172         { 0x40, "Bad Request" },
173         { 0x41, "Unauthorised" },
174         { 0x42, "Payment Required" },
175         { 0x43, "Forbidden" },
176         { 0x44, "Not Found" },
177         { 0x45, "Method Not Allowed" },
178         { 0x46, "Not Acceptable" },
179         { 0x47, "Proxy Authentication Required" },
180         { 0x48, "Request Timeout" },
181         { 0x49, "Conflict" },
182         { 0x4A, "Gone" },
183         { 0x4B, "Length Required" },
184         { 0x4C, "Precondition Failed" },
185         { 0x4D, "Request Entity Too Large" },
186         { 0x4E, "Request-URI Too Large" },
187         { 0x4F, "Unsupported Media Type" },
188
189         { 0x60, "Internal Server Error" },
190         { 0x61, "Not Implemented" },
191         { 0x62, "Bad Gateway" },
192         { 0x63, "Service Unavailable" },
193         { 0x64, "Gateway Timeout" },
194         { 0x65, "HTTP Version Not Supported" },
195         { 0x00, NULL }
196 };
197
198 static const value_string vals_content_types[] = {
199         { 0x00, "*/*" },
200         { 0x01, "text/*" },
201         { 0x02, "text/html" },
202         { 0x03, "text/plain" },
203         { 0x04, "text/x-hdml" },
204         { 0x05, "text/x-ttml" },
205         { 0x06, "text/x-vCalendar" },
206         { 0x07, "text/x-vCard" },
207         { 0x08, "text/vnd.wap.wml" },
208         { 0x09, "text/vnd.wap.wmlscript" },
209         { 0x0A, "text/vnd.wap.channel" },
210         { 0x0B, "Multipart/*" },
211         { 0x0C, "Multipart/mixed" },
212         { 0x0D, "Multipart/form-data" },
213         { 0x0E, "Multipart/byteranges" },
214         { 0x0F, "Multipart/alternative" },
215         { 0x10, "application/*" },
216         { 0x11, "application/java-vm" },
217         { 0x12, "application/x-www-form-urlencoded" },
218         { 0x13, "application/x-hdmlc" },
219         { 0x14, "application/vnd.wap.wmlc" },
220         { 0x15, "application/vnd.wap.wmlscriptc" },
221         { 0x16, "application/vnd.wap.channelc" },
222         { 0x17, "application/vnd.wap.uaprof" },
223         { 0x18, "application/vnd.wap.wtls-ca-certificate" },
224         { 0x19, "application/vnd.wap.wtls-user-certificate" },
225         { 0x1A, "application/x-x509-ca-cert" },
226         { 0x1B, "application/x-x509-user-cert" },
227         { 0x1C, "image/*" },
228         { 0x1D, "image/gif" },
229         { 0x1E, "image/jpeg" },
230         { 0x1F, "image/tiff" },
231         { 0x20, "image/png" },
232         { 0x21, "image/vnd.wap.wbmp" },
233         { 0x22, "application/vnd.wap.multipart.*" },
234         { 0x23, "application/vnd.wap.multipart.mixed" },
235         { 0x24, "application/vnd.wap.multipart.form-data" },
236         { 0x25, "application/vnd.wap.multipart.byteranges" },
237         { 0x26, "application/vnd.wap.multipart.alternative" },
238         { 0x27, "application/xml" },
239         { 0x28, "text/xml" },
240         { 0x29, "application/vnd.wap.wbxml" },
241         { 0x2A, "application/x-x968-cross-cert" },
242         { 0x2B, "application/x-x968-ca-cert" },
243         { 0x2C, "application/x-x968-user-cert" },
244         { 0x2D, "text/vnd.wap.si" },
245         { 0x2E, "application/vnd.wap.sic" },
246         { 0x2F, "text/vnd.wap.sl" },
247         { 0x30, "application/vnd.wap.slc" },
248         { 0x31, "text/vnd.wap.co" },
249         { 0x32, "application/vnd.wap.coc" },
250         { 0x33, "application/vnd.wap.multipart.related" },
251         { 0x34, "application/vnd.wap.sia" },
252         { 0x00, NULL }
253 };
254
255 static const value_string vals_languages[] = {
256         { 0x01, "Afar (aa)" },
257         { 0x02, "Abkhazian (ab)" },
258         { 0x03, "Afrikaans (af)" },
259         { 0x04, "Amharic (am)" },
260         { 0x05, "Arabic (ar)" },
261         { 0x06, "Assamese (as)" },
262         { 0x07, "Aymara (ay)" },
263         { 0x08, "Azerbaijani (az)" },
264         { 0x09, "Bashkir (ba)" },
265         { 0x0A, "Byelorussian (be)" },
266         { 0x0B, "Bulgarian (bg)" },
267         { 0x0C, "Bihari (bh)" },
268         { 0x0D, "Bislama (bi)" },
269         { 0x0E, "Bengali; Bangla (bn)" },
270         { 0x0F, "Tibetan (bo)" },
271         { 0x10, "Breton (br)" },
272         { 0x11, "Catalan (ca)" },
273         { 0x12, "Corsican (co)" },
274         { 0x13, "Czech (cs)" },
275         { 0x14, "Welsh (cy)" },
276         { 0x15, "Danish (da)" },
277         { 0x16, "German (de)" },
278         { 0x17, "Bhutani (dz)" },
279         { 0x18, "Greek (el)" },
280         { 0x19, "English (en)" },
281         { 0x1A, "Esperanto (eo)" },
282         { 0x1B, "Spanish (es)" },
283         { 0x1C, "Estonian (et)" },
284         { 0x1D, "Basque (eu)" },
285         { 0x1E, "Persian (fa)" },
286         { 0x1F, "Finnish (fi)" },
287         { 0x20, "Fiji (fj)" },
288         { 0x22, "French (fr)" },
289         { 0x24, "Irish (ga)" },
290         { 0x25, "Scots Gaelic (gd)" },
291         { 0x26, "Galician (gl)" },
292         { 0x27, "Guarani (gn)" },
293         { 0x28, "Gujarati (gu)" },
294         { 0x29, "Hausa (ha)" },
295         { 0x2A, "Hebrew (formerly iw) (he)" },
296         { 0x2B, "Hindi (hi)" },
297         { 0x2C, "Croatian (hr)" },
298         { 0x2D, "Hungarian (hu)" },
299         { 0x2E, "Armenian (hy)" },
300         { 0x30, "Indonesian (formerly in) (id)" },
301         { 0x47, "Maori (mi)" },
302         { 0x48, "Macedonian (mk)" },
303         { 0x49, "Malayalam (ml)" },
304         { 0x4A, "Mongolian (mn)" },
305         { 0x4B, "Moldavian (mo)" },
306         { 0x4C, "Marathi (mr)" },
307         { 0x4D, "Malay (ms)" },
308         { 0x4E, "Maltese (mt)" },
309         { 0x4F, "Burmese (my)" },
310         { 0x51, "Nepali (ne)" },
311         { 0x52, "Dutch (nl)" },
312         { 0x53, "Norwegian (no)" },
313         { 0x54, "Occitan (oc)" },
314         { 0x55, "(Afan) Oromo (om)" },
315         { 0x56, "Oriya (or)" },
316         { 0x57, "Punjabi (pa)" },
317         { 0x58, "Polish (po)" },
318         { 0x59, "Pashto, Pushto (ps)" },
319         { 0x5A, "Portuguese (pt)" },
320         { 0x5B, "Quechua (qu)" },
321         { 0x5D, "Kirundi (rn)" },
322         { 0x5E, "Romanian (ro)" },
323         { 0x5F, "Russian (ru)" },
324         { 0x60, "Kinyarwanda (rw)" },
325         { 0x61, "Sanskrit (sa)" },
326         { 0x62, "Sindhi (sd)" },
327         { 0x63, "Sangho (sg)" },
328         { 0x64, "Serbo-Croatian (sh)" },
329         { 0x65, "Sinhalese (si)" },
330         { 0x66, "Slovak (sk)" },
331         { 0x67, "Slovenian (sl)" },
332         { 0x68, "Samoan (sm)" },
333         { 0x69, "Shona (sn)" },
334         { 0x6A, "Somali (so)" },
335         { 0x6B, "Albanian (sq)" },
336         { 0x6C, "Serbian (sr)" },
337         { 0x6D, "Siswati (ss)" },
338         { 0x6E, "Sesotho (st)" },
339         { 0x6F, "Sundanese (su)" },
340         { 0x70, "Swedish (sv)" },
341         { 0x71, "Swahili (sw)" },
342         { 0x72, "Tamil (ta)" },
343         { 0x73, "Telugu (te)" },
344         { 0x74, "Tajik (tg)" },
345         { 0x75, "Thai (th)" },
346         { 0x76, "Tigrinya (ti)" },
347         { 0x81, "Nauru (na)" },
348         { 0x82, "Faeroese (fo)" },
349         { 0x83, "Frisian (fy)" },
350         { 0x84, "Interlingua (ia)" },
351         { 0x8C, "Rhaeto-Romance (rm)" },
352         { 0x00, NULL }
353 };
354
355 static const value_string vals_accept_ranges[] = {
356         { 0x80, "None" },
357         { 0x81, "Bytes" },
358         { 0x00, NULL }
359 };
360
361 static const value_string vals_cache_control[] = {
362         { 0x80, "No-cache" },
363         { 0x81, "No-store" },
364         { 0x82, "Max-age" },
365         { 0x83, "Max-stale" },
366         { 0x84, "Min-fresh" },
367         { 0x85, "Only-if-cached" },
368         { 0x86, "Public" },
369         { 0x87, "Private" },
370         { 0x88, "No-transform" },
371         { 0x89, "Must-revalidate" },
372         { 0x8A, "Proxy-revalidate" },
373         { 0x00, NULL }
374 };
375
376 static const value_string vals_transfer_encoding[] = {
377         { 0x80, "Chunked" },
378         { 0x00, NULL }
379 };
380
381 /*
382  * Windows appears to define DELETE.
383  */
384 #ifdef DELETE
385 #undef DELETE
386 #endif
387
388 enum {
389         RESERVED                = 0x00,
390         CONNECT                 = 0x01,
391         CONNECTREPLY    = 0x02,
392         REDIRECT                = 0x03,                 /* No sample data */
393         REPLY                   = 0x04,
394         DISCONNECT              = 0x05,
395         PUSH                    = 0x06,                 /* No sample data */
396         CONFIRMEDPUSH   = 0x07,                 /* No sample data */
397         SUSPEND                 = 0x08,                 /* No sample data */
398         RESUME                  = 0x09,                 /* No sample data */
399
400         GET                             = 0x40,
401         OPTIONS                 = 0x41,                 /* No sample data */
402         HEAD                    = 0x42,                 /* No sample data */
403         DELETE                  = 0x43,                 /* No sample data */
404         TRACE                   = 0x44,                 /* No sample data */
405
406         POST                    = 0x60,
407         PUT                             = 0x61,                 /* No sample data */
408 };
409
410 static void add_uri (proto_tree *, tvbuff_t *, guint, guint);
411 static void add_headers (proto_tree *, tvbuff_t *);
412 static void add_header (proto_tree *, tvbuff_t *, tvbuff_t *);
413 static guint get_value_length (tvbuff_t *, guint, guint *);
414 static guint add_content_type (proto_tree *, tvbuff_t *, guint, guint *);
415 static gint get_date_value (tvbuff_t * ,guint ,struct timeval *);
416 static void add_date_value (tvbuff_t * ,guint ,proto_tree * ,int ,
417         tvbuff_t * ,guint ,guint ,struct timeval *, const char *);
418 static guint add_parameter (proto_tree *, tvbuff_t *, guint);
419 static guint add_parameter_charset (proto_tree *, tvbuff_t *, guint, guint);
420 static void add_post_data (proto_tree *, tvbuff_t *, guint);
421 static void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
422
423 /* Code to actually dissect the packets */
424 static void
425 dissect_wsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
426 {
427         frame_data *fdata = pinfo->fd;
428         int offset = 0;
429
430         guint8 pdut;
431         guint count = 0;
432         guint value = 0;
433         guint uriLength = 0;
434         guint uriStart = 0;
435         guint capabilityLength = 0;
436         guint capabilityStart = 0;
437         guint headersLength = 0;
438         guint headerLength = 0;
439         guint headerStart = 0;
440         guint nextOffset = 0;
441         guint contentTypeStart = 0;
442         guint contentType = 0;
443         tvbuff_t *tmp_tvb;
444
445 /* Set up structures we will need to add the protocol subtree and manage it */
446         proto_item *ti;
447         proto_tree *wsp_tree;
448 /*      proto_tree *wsp_header_fixed; */
449         proto_tree *wsp_capabilities;
450         
451 /* This field shows up as the "Info" column in the display; you should make
452    it, if possible, summarize what's in the packet, so that a user looking
453    at the list of packets can tell what type of packet it is. */
454     
455         /* Display protocol type depending on the port */
456         if (check_col(fdata, COL_PROTOCOL)) 
457         {
458                 switch ( pinfo->match_port )
459                 {
460                         case UDP_PORT_WSP:
461                                 col_set_str(fdata, COL_PROTOCOL, "WSP" );
462                                 break;
463                         case UDP_PORT_WTLS_WSP:
464                                 col_set_str(fdata, COL_PROTOCOL, "WTLS+WSP" );
465                                 break;
466                 }
467         }
468
469         /* Clear the Info column before we fetch anything from the packet */
470         if (check_col(fdata, COL_INFO))
471         {
472                 col_clear(fdata, COL_INFO);
473         }
474
475         /* Connection-less mode has a TID first */
476         if (    (pinfo->match_port == UDP_PORT_WSP) ||
477                         (pinfo->match_port == UDP_PORT_WTLS_WSP))
478         {
479                 offset++;
480         };
481
482         /* Find the PDU type */
483         pdut = tvb_get_guint8 (tvb, offset);
484
485         /* Develop the string to put in the Info column */
486         if (check_col(fdata, COL_INFO))
487         {
488                 col_add_fstr(fdata, COL_INFO, "WSP %s",
489                         val_to_str (pdut, vals_pdu_type, "Unknown PDU type (0x%02x)"));
490         };
491
492 /* In the interest of speed, if "tree" is NULL, don't do any work not
493    necessary to generate protocol tree items. */
494         if (tree) {
495                 ti = proto_tree_add_item(tree, proto_wsp, tvb, 0,
496                     tvb_length(tvb), bo_little_endian);
497                 wsp_tree = proto_item_add_subtree(ti, ett_wsp);
498
499 /* Code to process the packet goes here */
500 /*
501                         wsp_header_fixed = proto_item_add_subtree(ti, ett_header );
502 */
503
504                         /* Add common items: only TID and PDU Type */
505
506                         /* If this is connectionless, then the TID Field is always first */
507                         if (    (pinfo->match_port == UDP_PORT_WSP) ||
508                                         (pinfo->match_port == UDP_PORT_WTLS_WSP))
509                         {
510                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_tid,tvb,
511                                         0,1,bo_little_endian);
512                         }
513
514                         ti = proto_tree_add_item(
515                                         wsp_tree,               /* tree */
516                                         hf_wsp_header_pdu_type,         /* id */
517                                         tvb, 
518                                         offset++,                       /* start of high light */
519                                         1,                              /* length of high light */
520                                         bo_little_endian                                /* value */
521                              );
522
523                         switch (pdut)
524                         {
525                                 case CONNECT:
526                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
527                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
528                                         offset++;
529                                         capabilityStart = offset;
530                                         count = 0;      /* Initialise count */
531                                         capabilityLength = tvb_get_guintvar (tvb, offset, &count);
532                                         offset += count;
533                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
534
535                                         headerStart = offset;
536                                         count = 0;      /* Initialise count */
537                                         headerLength = tvb_get_guintvar (tvb, offset, &count);
538                                         offset += count;
539                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
540                                         if (capabilityLength > 0)
541                                         {
542                                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_capabilities_section,tvb,offset,capabilityLength,bo_little_endian);
543                                                 wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
544                                                 offset += capabilityLength;
545                                         }
546
547                                         if (headerLength > 0)
548                                         {
549                                                 tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
550                                                 add_headers (wsp_tree, tmp_tvb);
551                                         }
552
553                                         break;
554
555                                 case CONNECTREPLY:
556                                         count = 0;      /* Initialise count */
557                                         value = tvb_get_guintvar (tvb, offset, &count);
558                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
559                                         offset += count;
560
561                                         capabilityStart = offset;
562                                         count = 0;      /* Initialise count */
563                                         capabilityLength = tvb_get_guintvar (tvb, offset, &count);
564                                         offset += count;
565                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
566
567                                         headerStart = offset;
568                                         count = 0;      /* Initialise count */
569                                         headerLength = tvb_get_guintvar (tvb, offset, &count);
570                                         offset += count;
571                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
572                                         if (capabilityLength > 0)
573                                         {
574                                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_capabilities_section,tvb,offset,capabilityLength,bo_little_endian);
575                                                 wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
576                                                 offset += capabilityLength;
577                                         }
578
579                                         if (headerLength > 0)
580                                         {
581
582                                                 /*
583                                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_headers_section,tvb,offset,headerLength,bo_little_endian);
584                                                 wsp_headers = proto_item_add_subtree( ti, ett_headers );
585                                                 */
586                                                 tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
587                                                 add_headers (wsp_tree, tmp_tvb);
588                                         }
589
590                                         break;
591
592                                 case DISCONNECT:
593                                         count = 0;      /* Initialise count */
594                                         value = tvb_get_guintvar (tvb, offset, &count);
595                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
596                                         break;
597
598                                 case GET:
599                                         count = 0;      /* Initialise count */
600                                         /* Length of URI and size of URILen field */
601                                         value = tvb_get_guintvar (tvb, offset, &count);
602                                         nextOffset = offset + count;
603                                         add_uri (wsp_tree, tvb, offset, nextOffset);
604                                         offset += (value+count); /* VERIFY */
605                                         tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
606                                         add_headers (wsp_tree, tmp_tvb);
607                                         break;
608
609                                 case POST:
610                                         uriStart = offset;
611                                         count = 0;      /* Initialise count */
612                                         uriLength = tvb_get_guintvar (tvb, offset, &count);
613                                         headerStart = uriStart+count;
614                                         count = 0;      /* Initialise count */
615                                         headersLength = tvb_get_guintvar (tvb, headerStart, &count);
616                                         offset = headerStart + count;
617
618                                         add_uri (wsp_tree, tvb, uriStart, offset);
619                                         offset += uriLength;
620
621                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,bo_little_endian);
622
623                                         contentTypeStart = offset;
624                                         nextOffset = add_content_type (wsp_tree, tvb, offset, &contentType);
625
626                                         /* Add headers subtree that will hold the headers fields */
627                                         /* Runs from nextOffset for value-(length of content-type field)*/
628                                         headerLength = headersLength-(nextOffset-contentTypeStart);
629                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
630                                         add_headers (wsp_tree, tmp_tvb);
631
632                                         /* TODO: Post DATA */
633                                         /* Runs from start of headers+headerLength to END_OF_FRAME */
634                                         offset = nextOffset+headerLength;
635                                         tmp_tvb = tvb_new_subset (tvb, offset, tvb_reported_length (tvb)-offset, tvb_reported_length (tvb)-offset);
636                                         add_post_data (wsp_tree, tmp_tvb, contentType);
637                                         break;
638
639                                 case REPLY:
640                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
641                                         count = 0;      /* Initialise count */
642                                         value = tvb_get_guintvar (tvb, offset+1, &count);
643                                         nextOffset = offset + 1 + count;
644                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,value);
645
646                                         contentTypeStart = nextOffset;
647                                         nextOffset = add_content_type (wsp_tree, tvb, nextOffset, &contentType);
648
649                                         /* Add headers subtree that will hold the headers fields */
650                                         /* Runs from nextOffset for value-(length of content-type field)*/
651                                         headerLength = value-(nextOffset-contentTypeStart);
652                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
653                                         add_headers (wsp_tree, tmp_tvb);
654                                         offset += count+value+1;
655
656                                         /* TODO: Data - decode WMLC */
657                                         /* Runs from offset+1+count+value+1 to END_OF_FRAME */
658                                         if (offset < tvb_reported_length (tvb))
659                                         {
660                                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,END_OF_FRAME,bo_little_endian);
661                                         }
662                                         break;
663                         }
664         }
665 }
666
667 static void
668 add_uri (proto_tree *tree, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
669 {
670         proto_item *ti;
671         guint8 terminator = 0;
672         char *newBuffer;
673
674         guint count = 0;
675         guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
676
677         ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
678
679         /* If string doesn't end with a 0x00, we need to add one to be on the safe side */
680         terminator = tvb_get_guint8 (tvb, URIOffset+uriLen-1);
681         if (terminator != 0)
682         {
683                 newBuffer = g_malloc (uriLen+1);
684                 strncpy (newBuffer, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
685                 newBuffer[uriLen] = 0;
686                 ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer);
687                 g_free (newBuffer);
688         }
689         else
690         {
691                 ti = proto_tree_add_item (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,bo_little_endian);
692         }
693 }
694
695 static void
696 add_headers (proto_tree *tree, tvbuff_t *tvb)
697 {
698         proto_item *ti;
699         proto_tree *wsp_headers;
700         guint offset = 0;
701         guint headersLen = tvb_reported_length (tvb);
702         guint8 headerStart = 0;
703         guint peek = 0;
704         tvbuff_t *header_buff;
705         tvbuff_t *value_buff;
706         guint count = 0;
707         guint valueStart = 0;
708         guint valueEnd = 0;
709
710 #ifdef DEBUG
711         fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, headersLen);
712 #endif
713
714         /* End of buffer */
715         if (headersLen <= 0)
716         {
717                 return;
718         }
719
720 #ifdef DEBUG
721         fprintf (stderr, "dissect_wsp: Headers to process\n");
722 #endif
723
724         ti = proto_tree_add_item (tree, hf_wsp_headers_section,tvb,offset,headersLen,bo_little_endian);
725         wsp_headers = proto_item_add_subtree( ti, ett_headers );
726
727         /* Parse Headers */
728
729         while (offset < headersLen)
730         {
731                 /* Loop round each header */
732                 headerStart = offset;
733                 peek = tvb_get_guint8 (tvb, headerStart);
734
735                 if (peek < 32)          /* Short-cut shift delimeter */
736                 {
737                         fprintf (stderr, "dissect_wsp: header: short-cut shift %d (0x%02X)\n", peek, peek);
738                         offset++;
739                 }
740                 else if (peek == 0x7F)  /* Shift delimeter */
741                 {
742                         fprintf (stderr, "dissect_wsp: header: shift delimeter %d (0x%02X)\n", peek, peek);
743                         offset++;
744                 }
745                 else if (peek < 127)
746                 {
747 #ifdef DEBUG
748                         fprintf (stderr, "dissect_wsp: header: application-header start %d (0x%02X)\n", peek, peek);
749 #endif
750                         while (tvb_get_guint8 (tvb, offset++)) { /* Do nothing, just look for NULL */ }
751                 }
752                 else if (peek & 0x80)   /* Well-known header */
753                 {
754 #ifdef DEBUG
755                         fprintf (stderr, "dissect_wsp: header: well-known %d (0x%02X)\n", peek, peek);
756 #endif
757                         offset++;
758                 }
759
760                 /* Get value part of header */
761                 valueStart = offset;
762                 peek = tvb_get_guint8 (tvb, valueStart);
763                 if (peek <= 30)
764                 {
765 #ifdef DEBUG
766                         fprintf (stderr, "dissect_wsp: Looking for %d octets\n", peek);
767 #endif
768                         /* VERIFY: valueStart++; */
769                         valueEnd = offset+1+peek;
770                         offset += (peek+1);
771                 }
772                 else if (peek == 31)
773                 {
774 #ifdef DEBUG
775                         fprintf (stderr, "dissect_wsp: Looking for uintvar octets\n");
776 #endif
777                         count = 0;      /* Initialise count */
778                         tvb_get_guintvar (tvb, valueStart, &count);
779                         valueEnd = offset+1+count;
780                         offset += (count+1);
781                 }
782                 else if (peek <= 127)
783                 {
784 #ifdef DEBUG
785                         fprintf (stderr, "dissect_wsp: Looking for NULL-terminated string\n");
786 #endif
787                         valueEnd = valueStart+1;
788                         while (tvb_get_guint8 (tvb, valueEnd++)) { /* Do nothing, just look for NULL */ }
789                         offset = valueEnd;
790                 }
791                 else
792                 {
793 #ifdef DEBUG
794                         fprintf (stderr, "dissect_wsp: Value is %d\n", (peek & 0x7F));
795 #endif
796                         valueEnd = offset+1;
797                         offset++;
798                 }
799 #ifdef DEBUG
800                 fprintf (stderr, "dissect_wsp: Creating value buffer from offset %d, size=%d\n", headerStart, (offset-headerStart));
801 #endif
802
803                 header_buff = tvb_new_subset (tvb, headerStart, (offset-headerStart), (offset-headerStart));
804                 value_buff = tvb_new_subset (tvb, valueStart, (valueEnd-valueStart), (valueEnd-valueStart));
805
806                 add_header (wsp_headers, header_buff, value_buff);
807         }
808 }
809
810 static void
811 add_header (proto_tree *tree, tvbuff_t *header_buff, tvbuff_t *value_buff)
812 {
813         guint offset = 0;
814         guint valueStart = 0;
815         guint8 headerType = 0;
816         proto_item *ti;
817         guint headerLen = tvb_reported_length (header_buff);
818         guint valueLen = tvb_reported_length (value_buff);
819         guint peek = 0;
820         struct timeval timeValue;
821         guint value = 0;
822         guint valueLength = 0;
823         char valString[100];
824         char *valMatch = NULL;
825         double q_value = 1.0;
826
827         /* Initialise time values */
828         timeValue.tv_sec=0;
829         timeValue.tv_usec = 0;
830
831         headerType = tvb_get_guint8 (header_buff, 0);
832         peek = tvb_get_guint8 (value_buff, 0);
833 #ifdef DEBUG
834         fprintf (stderr, "dissect_wsp: Got header 0x%02x\n", headerType);
835         fprintf (stderr, "dissect_wsp: First value octet is 0x%02x\n", peek);
836 #endif
837
838         if (headerType == 0x7F)
839         {
840         }
841         else if (headerType < 0x1F)
842         {
843         }
844         else if (headerType & 0x80)
845         {
846                 headerType = headerType & 0x7F;
847                 switch (headerType)
848                 {
849                         case 0x00:              /* Accept */
850                                 if (peek & 0x80)
851                                 {
852                                         proto_tree_add_uint (tree, hf_wsp_header_accept, header_buff, offset, headerLen, (peek & 0x7F));
853                                 }
854                                 else
855                                 {
856                                         proto_tree_add_string (tree, hf_wsp_header_accept_str,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
857                                 }
858                                 break;
859
860                         case 0x01:              /* Accept-Charset */
861                                 if (peek <= 31)                         /* Accept-charset-general-form */
862                                 {
863                                         /* Get Value-Length */
864                                         valueLength = get_value_length (value_buff, offset,
865                                                 &valueStart);
866                                         offset = valueStart;
867
868                                         peek = tvb_get_guint8 (value_buff, offset);
869                                         if ((peek >= 0x80) || (peek <= 30))     /* Well-known-charset */
870                                         {
871                                                 if (peek == 0x80)               /* Any */
872                                                 {
873                                                         value = peek;
874                                                         offset++;
875                                                 }
876                                                 else if (peek & 0x80)   /* Short-Integer */
877                                                 {
878                                                         value = peek & 0x7F;
879                                                         offset++;
880                                                 }
881                                                 else if (peek <= 30)    /* Long-Integer */
882                                                 {
883                                                         offset++;
884         
885                                                         switch (peek)
886                                                         {
887                                                                 case 1:
888                                                                         value = tvb_get_guint8 (value_buff, offset);
889                                                                         break;
890                                                                 case 2:
891                                                                         value = tvb_get_ntohs (value_buff, offset);
892                                                                         break;
893                                                                 case 3:
894                                                                         value = tvb_get_ntoh24 (value_buff, offset);
895                                                                         break;
896                                                                 case 4:
897                                                                         value = tvb_get_ntohl (value_buff, offset);
898                                                                         break;
899                                                                 default:
900                                                                         /* TODO: Need to read peek octets */
901                                                                         value = 0;
902                                                                         fprintf (stderr, "dissect_wsp: accept-charset size %d NYI\n", peek);
903                                                                         break;
904                                                         }
905                                                         offset += peek;
906                                                 }
907                                                 valMatch = match_strval(value, vals_character_sets);
908                                         }
909                                         else                                            /* Assume Token-text */
910                                         {
911                                                 fprintf (stderr, "dissect_wsp: Accept-Charset Token-text NYI\n");
912                                         }
913
914                                         /* Any remaining data relates to Q-Value */
915                                         if (offset < valueLen)
916                                         {
917                                                 peek = tvb_get_guintvar (value_buff, offset, NULL);
918                                                 if (peek <= 100) {
919                                                         peek = (peek - 1) * 10;
920                                                 }
921                                                 else {
922                                                         peek -= 100;
923                                                 }
924                                                 q_value = peek/1000.0;
925                                         }
926
927                                         /* Build string including Q values if present */
928                                         if (q_value == 1.0)                     /* Default */
929                                         {
930                                                 if (valMatch == NULL)
931                                                 {
932                                                         snprintf (valString, 100, "Unknown (%X)", peek);
933                                                 }
934                                                 else
935                                                 {
936                                                         snprintf (valString, 100, "%s", valMatch);
937                                                 }
938                                         }
939                                         else
940                                         {
941                                                 if (valMatch == NULL)
942                                                 {
943                                                         snprintf (valString, 100, "Unknown (%X); Q=%5.3f", peek,q_value);
944                                                 }
945                                                 else
946                                                 {
947                                                         snprintf (valString, 100, "%s; Q=%5.3f", valMatch,q_value);
948                                                 }
949                                         }
950
951                                         /* Add string to tree */
952                                         proto_tree_add_string (tree, hf_wsp_header_accept_charset_str,
953                                                 header_buff, 0, headerLen, valString);
954                                 }
955                                 else                                            /* Constrained-charset */
956                                 {
957                                         if (peek == 0x80)               /* Any-charset */
958                                         {
959                                                 proto_tree_add_string (tree, hf_wsp_header_accept_charset,
960                                                         header_buff, offset, headerLen,
961                                                         "*");
962                                         }
963                                         else if (peek & 0x80)   /* Short-Integer */
964                                         {
965                                                 proto_tree_add_uint (tree, hf_wsp_header_accept_charset,
966                                                         header_buff, offset, headerLen, (peek & 0x7F) );
967                                         }
968                                         else                                    /* Assume *TEXT */
969                                         {
970                                                 proto_tree_add_string (tree, hf_wsp_header_accept_charset,
971                                                         header_buff, offset, headerLen,
972                                                         tvb_get_ptr (value_buff, 0, valueLen));
973                                         }
974                                 }
975                                 break;
976
977                         case 0x03:              /* Accept-Language */
978                                 if (peek < 31)
979                                 {
980                                         /* Peek contains the number of octets to follow */
981                                         switch (peek)
982                                         {
983                                                 case 1:
984                                                         proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, 
985                                                                 headerLen, tvb_get_guint8 (value_buff, 1) );
986                                                 break;
987                                                 case 2:
988                                                         proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, 
989                                                                 headerLen, tvb_get_ntohs (value_buff, 1) );
990                                                 break;
991                                                 case 4:
992                                                         proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, 
993                                                                 headerLen, tvb_get_ntohl (value_buff, 1) );
994                                                 break;
995                                                 default:
996                                                         fprintf (stderr, "dissect_wsp: accept-language size %d NYI\n", peek);
997                                         }
998                                 }
999                                 else if (peek & 0x80)
1000                                 {
1001                                         proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, headerLen, (peek & 0x7F) );
1002                                 }
1003                                 else
1004                                 {
1005                                         proto_tree_add_string (tree, hf_wsp_header_accept_language_str, header_buff, offset,headerLen,
1006                                                 tvb_get_ptr (value_buff, 0, valueLen));
1007                                 }
1008                                 break;
1009
1010                         case 0x04:              /* Accept-Ranges */
1011                                 if ((peek == 128) || (peek == 129))
1012                                 {
1013                                         proto_tree_add_uint (tree, hf_wsp_header_accept_ranges, header_buff, offset, headerLen, peek);
1014                                 }
1015                                 else
1016                                 {
1017                                         fprintf (stderr, "dissect_wsp: accept-ranges NYI\n");
1018                                 }
1019                                 
1020                                 break;
1021
1022                         case 0x05:              /* Age */
1023                                 switch (valueLen)
1024                                 {
1025                                         case 1:
1026                                                 proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_guint8 (value_buff, 0));
1027                                                 break;
1028                                         case 2:
1029                                                 proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntohs (value_buff, 0));
1030                                                 break;
1031                                         case 3:
1032                                                 proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntoh24 (value_buff, 0));
1033                                                 break;
1034                                         case 4:
1035                                                 proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntohl (value_buff, 0));
1036                                                 break;
1037                                 };
1038                                 break;
1039
1040                         case 0x08:              /* Cache-Control */
1041                                 if (peek & 0x80)
1042                                 {
1043                                         if (valueLen == 1)      /* Well-known value */
1044                                         {
1045                                                 proto_tree_add_uint (tree, hf_wsp_header_cache_control, header_buff, offset, headerLen, peek);
1046                                         }
1047                                         else
1048                                         {
1049                                                 if ((peek == 0x82) || (peek == 0x83) || (peek == 0x84)) /* Delta seconds value to follow */
1050                                                 {
1051                                                         value = tvb_get_guint8 (value_buff, 1);
1052                                                         if (value & 0x80)
1053                                                         {
1054                                                                 proto_tree_add_text (tree, header_buff, 0,
1055                                                                         headerLen, "Cache-Control: %s %d (0x%02X)",
1056                                                                 val_to_str (peek, vals_cache_control,
1057                                                                         "Unknown (0x%02x)"),
1058                                                                 (value & 0x7F), peek);
1059                                                         }
1060                                                         else
1061                                                         {
1062                                                                 fprintf (stderr, "dissect_wsp: Cache-Control integer value Delta seconds NYI\n");
1063                                                         }
1064                                                 }
1065                                                 else if ((peek == 0x80) || (peek == 0x87))      /* Fields to follow */
1066                                                 {
1067                                                         fprintf (stderr, "dissect_wsp: Cache-Control field values NYI\n");
1068                                                 }
1069                                                 else
1070                                                 {
1071                                                         fprintf (stderr, "dissect_wsp: Cache-Control cache extension NYI\n");
1072                                                 }
1073                                         }
1074                                 }
1075                                 else
1076                                 {
1077                                         fprintf (stderr, "dissect_wsp: Cache-Control cache extension NYI\n");
1078                                 }
1079                                 break;
1080                                 
1081                         case 0x0D:              /* Content-Length */
1082                                 if (peek < 31)
1083                                 {
1084                                         switch (peek)
1085                                         {
1086                                                 case 1:
1087                                                         proto_tree_add_uint (tree,
1088                                                                 hf_wsp_header_content_length, header_buff, offset,
1089                                                                 headerLen, tvb_get_guint8 (value_buff, 1) );
1090                                                         break;
1091                                                 case 2:
1092                                                         proto_tree_add_uint (tree,
1093                                                                 hf_wsp_header_content_length, header_buff, offset,
1094                                                                 headerLen, tvb_get_ntohs (value_buff, 1) );
1095                                                         break;
1096                                                 case 3:
1097                                                         proto_tree_add_uint (tree,
1098                                                                 hf_wsp_header_content_length, header_buff, offset,
1099                                                                 headerLen, (tvb_get_ntohs (value_buff, 1) << 8) +
1100                                                                 tvb_get_guint8 (value_buff, 3) );
1101                                                         break;
1102                                                 case 4:
1103                                                         proto_tree_add_uint (tree,
1104                                                                 hf_wsp_header_content_length, header_buff, offset,
1105                                                                 headerLen, tvb_get_ntohl (value_buff, 1) );
1106                                                         break;
1107                                                 default:
1108                                                         fprintf (stderr, "dissect_wsp: accept-charset size %d NYI\n", peek);
1109                                         }
1110                                 }
1111                                 else if (peek & 0x80)
1112                                 {
1113                                         proto_tree_add_uint (tree, hf_wsp_header_content_length, header_buff, offset, headerLen, (peek & 0x7F));
1114                                 }
1115                                 else
1116                                 {
1117                                         fprintf (stderr, "dissect_wsp: Content-Length long-integer size NYI\n");
1118                                 }
1119                                 break;
1120                                 
1121                         case 0x12:              /* Date */
1122                                 add_date_value (value_buff, 0, tree,
1123                                         hf_wsp_header_date, header_buff, offset,
1124                                         headerLen, &timeValue, "Date");
1125                                 break;
1126
1127                         case 0x13:              /* Etag */
1128                                 ti = proto_tree_add_string (tree, hf_wsp_header_etag,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
1129                                 break;
1130
1131                         case 0x14:              /* Expires */
1132                                 add_date_value (value_buff, 0, tree,
1133                                         hf_wsp_header_expires, header_buff, offset,
1134                                         headerLen, &timeValue, "Expires");
1135                                 break;
1136
1137                         case 0x17:              /* If-Modified-Since */
1138                                 add_date_value (value_buff, 0, tree,
1139                                         hf_wsp_header_if_modified_since, header_buff, offset,
1140                                         headerLen, &timeValue, "If-Modified-Since");
1141                                 break;
1142                                 
1143                         case 0x1C:              /* Location */
1144                                 ti = proto_tree_add_string (tree, hf_wsp_header_location,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
1145                                 break;
1146
1147                         case 0x1D:              /* Last-Modified */
1148                                 add_date_value (value_buff, 0, tree,
1149                                         hf_wsp_header_last_modified, header_buff, offset,
1150                                         headerLen, &timeValue, "Last-Modified");
1151                                 break;
1152                                 
1153                         case 0x1F:              /* Pragma */
1154                                 if (peek == 0x80)
1155                                 {
1156                                         proto_tree_add_text (tree, header_buff, 0, headerLen, "Pragma: No-cache");
1157                                 }
1158                                 else
1159                                 {
1160                                         proto_tree_add_text (tree, header_buff, 0, headerLen, "Unsupported Header (0x%02X)", (tvb_get_guint8 (header_buff, 0) & 0x7F));
1161                                 }
1162                                 break;
1163                                 
1164                         case 0x26:              /* Server */
1165                                 ti = proto_tree_add_string (tree, hf_wsp_header_server,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
1166                                 break;
1167
1168                         case 0x27:              /* Transfer encoding */
1169                                 if (peek & 0x80)
1170                                 {
1171                                         proto_tree_add_uint (tree, hf_wsp_header_transfer_encoding,
1172                                                 header_buff, offset, headerLen, peek);
1173                                 }
1174                                 else
1175                                 {
1176                                         proto_tree_add_string (tree,
1177                                                 hf_wsp_header_transfer_encoding_str, header_buff, offset,
1178                                                 headerLen,tvb_get_ptr (value_buff, 0, valueLen));
1179                                 }
1180                                 break;
1181
1182                         case 0x29:              /* User-Agent */
1183                                 ti = proto_tree_add_string (tree, hf_wsp_header_user_agent,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
1184                                 break;
1185
1186                         case 0x2B:              /* Via */
1187                                 ti = proto_tree_add_string (tree, hf_wsp_header_via, header_buff,
1188                                         offset, headerLen, tvb_get_ptr (value_buff, 0, valueLen));
1189                                 break;
1190
1191                         default:
1192                                 ti = proto_tree_add_text (tree, header_buff, 0, headerLen, "Unsupported Header (0x%02X)", (tvb_get_guint8 (header_buff, 0) & 0x7F));
1193                                 break;
1194                 }
1195         }
1196         else
1197         {
1198                 /* Special case header X-WAP.TOD that is sometimes followed
1199                  * by a 4-byte date value */
1200                 if (strncasecmp ("x-wap.tod", tvb_get_ptr (header_buff, 0, headerLen), 9) == 0)
1201                 {
1202                         peek = tvb_get_guint8 (value_buff,offset);
1203                         if (peek < 31) 
1204                         {
1205                                 timeValue.tv_usec = 0;
1206                                 switch (peek)
1207                                 {
1208                                         case 1:
1209                                                 timeValue.tv_sec = tvb_get_guint8 (value_buff, 1);
1210                                                 break;
1211                                         case 2:
1212                                                 timeValue.tv_sec = tvb_get_ntohs (value_buff, 1);
1213                                                 break;
1214                                         case 3:
1215                                                 timeValue.tv_sec = tvb_get_ntoh24 (value_buff, 1);
1216                                                 break;
1217                                         case 4:
1218                                                 timeValue.tv_sec = tvb_get_ntohl (value_buff, 1);
1219                                                 break;
1220                                         default:
1221                                                 timeValue.tv_sec = 0;
1222                                                 fprintf (stderr, "dissect_wsp: X-WAP.TOD NYI\n");
1223                                                 break;
1224                                 }
1225                                 ti = proto_tree_add_time (tree, hf_wsp_header_x_wap_tod, header_buff, offset, headerLen, &timeValue);
1226                         }
1227                         else
1228                         {
1229                                 fprintf (stderr, "dissect_wsp: X-WAP.TOD peek %X NYI\n",peek);
1230                         }
1231                 }
1232                 else
1233                 {
1234                         ti = proto_tree_add_text (tree, header_buff, 0, headerLen, "%s: %s", tvb_get_ptr (header_buff, 0, headerLen), tvb_get_ptr (value_buff, 0, valueLen));
1235                 }
1236         }
1237
1238 }
1239
1240 static guint
1241 get_value_length (tvbuff_t *tvb, guint offset, guint *nextOffset)
1242 {
1243         guint value = 0;
1244         guint count = 0;
1245         guint octet = tvb_get_guint8 (tvb, offset);
1246
1247         if (octet <= 30)        /* Short length */
1248         {
1249                 value = octet;
1250                 *nextOffset = offset+1;
1251         }
1252         else if (octet == 31)
1253         {
1254                 value = tvb_get_guintvar (tvb, offset+1, &count);
1255                 *nextOffset = offset+1+count;
1256         }
1257         else
1258         {
1259                 fprintf (stderr, "dissect_wsp: get_value_length: case NYI\n");
1260         }
1261
1262         return (value);
1263 }
1264
1265 static guint
1266 add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset, guint *contentType)
1267 {
1268         proto_tree *contentTypeTree;
1269         guint nextOffset = offset;
1270         guint fieldLength = 0;
1271         guint octet = tvb_get_guint8 (tvb, offset);
1272         guint totalSizeOfField = 0;
1273
1274         if (octet <= 31)
1275         {
1276                 fieldLength = get_value_length (tvb, offset, &nextOffset);
1277                 totalSizeOfField = (nextOffset-offset)+fieldLength;
1278         }
1279         else if (octet & 0x80)
1280         {
1281                 fieldLength = 1;
1282                 totalSizeOfField = 1;
1283         }
1284         else
1285         {
1286                 fprintf (stderr, "dissect-wsp: Content-type is un-supported\n");
1287         }
1288
1289         *contentType = (tvb_get_guint8 (tvb, nextOffset) & 0x7F);
1290         contentTypeTree = proto_tree_add_uint (tree, hf_wsp_content_type, tvb, offset, totalSizeOfField, (tvb_get_guint8(tvb,nextOffset++) & 0x7F));
1291
1292         while (nextOffset < (offset+totalSizeOfField))
1293         {
1294                 /* add_parameter */
1295                 nextOffset = add_parameter (contentTypeTree, tvb, nextOffset);
1296         }
1297
1298         return (offset+totalSizeOfField);
1299 }
1300
1301 /* Utility function to extract date values from the packet */
1302 static gint
1303 get_date_value (tvbuff_t *buffer, guint offset, struct timeval *timeValue)
1304 {
1305         guint ShortLength = 0;
1306
1307         /* Initialise time values */
1308         timeValue->tv_sec=0;
1309         timeValue->tv_usec = 0;
1310
1311         /* Date values are encoded as: Short-length Multi-octet-integer
1312          * Where Short-length = 0-30
1313          */
1314         ShortLength = tvb_get_guint8 (buffer, offset++);
1315         if (ShortLength > 30)
1316         {
1317                 fprintf (stderr, "dissect_wsp: Invalid Date-value (Short-length=%d)\n",
1318                         ShortLength);
1319                 return (-1);
1320         }
1321
1322         switch (ShortLength)
1323         {
1324                 case 1:
1325                         timeValue->tv_sec = tvb_get_guint8 (buffer, offset);
1326                         break;
1327                 case 2:
1328                         timeValue->tv_sec = tvb_get_ntohs (buffer, offset);
1329                         break;
1330                 case 3:
1331                         timeValue->tv_sec = tvb_get_ntoh24 (buffer, offset);
1332                         break;
1333                 case 4:
1334                         timeValue->tv_sec = tvb_get_ntohl (buffer, offset);
1335                         break;
1336                 default:
1337                         fprintf (stderr, "dissect_wsp: Date-value Short-length of %d NYI\n",
1338                                 ShortLength);
1339                         return (-1);
1340                         break;
1341         }
1342
1343         return (0);
1344 }
1345
1346 /* Utility function to add a date value to the protocol tree */
1347 static void
1348 add_date_value (tvbuff_t *buffer, guint offset, proto_tree *tree,
1349                 int header, tvbuff_t *headerBuffer, guint headerOffset,
1350                 guint headerLen, struct timeval *timeValue, const char *fieldName)
1351 {
1352         /* Attempt to get the date value from the buffer */
1353         if (get_date_value (buffer, offset, timeValue) == 0)
1354         {
1355                 /* If successful, add it to the protocol tree */
1356                 proto_tree_add_time (tree, header, headerBuffer, headerOffset,
1357                         headerLen, timeValue);
1358         }
1359         else
1360         {
1361                 fprintf (stderr, "dissect_wsp: Invalid %s value\n", fieldName);
1362         }
1363 }
1364
1365 static guint
1366 add_parameter (proto_tree *tree, tvbuff_t *tvb, guint offset)
1367 {
1368         guint octet = tvb_get_guint8 (tvb, offset);
1369         if (octet & 0x80)       /* Short integer */
1370         {
1371                 offset++;
1372                 octet = octet & 0x7F;
1373                 switch ( octet )
1374                 {
1375                         case 0x01:
1376                                 offset = add_parameter_charset (tree, tvb, offset, offset-1);
1377                                 break;
1378
1379                         default:
1380                                 fprintf (stderr, "dissect-wsp: add_parameter octet=0x%02x\n", octet);
1381                 };
1382         }
1383         else
1384         {
1385                 fprintf (stderr, "dissect-wsp: add_parameter octet=0x%02x\n", octet);
1386         }
1387
1388         return (offset);
1389 }
1390
1391 static guint
1392 add_parameter_charset (proto_tree *tree, tvbuff_t *tvb, guint offset, guint startOffset)
1393 {
1394         guint octet = tvb_get_guint8 (tvb, offset);
1395         if (octet < 31)
1396         {
1397                 offset += octet+1;
1398                 proto_tree_add_item (tree, hf_wsp_parameter_well_known_charset, tvb, startOffset+1, octet, bo_big_endian);
1399         }
1400         else if (octet & 0x80)
1401         {
1402                 offset++;
1403                 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset, tvb, startOffset, offset-startOffset, (octet & 0x7F));
1404         }
1405
1406         return offset;
1407 }
1408
1409 static void
1410 add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType)
1411 {
1412         guint offset = 0;
1413         guint variableStart = 0;
1414         guint variableEnd = 0;
1415         guint valueStart = 0;
1416         guint valueEnd = 0;
1417         guint8 peek = 0;
1418         proto_item *ti;
1419         
1420         /* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,END_OF_FRAME,bo_little_endian); */
1421         ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_reported_length(tvb),bo_little_endian);
1422
1423         if (contentType == 0x12)        /* URL Encoded data */
1424         {
1425                 /* Iterate through post data */
1426                 for (offset = 0; offset < tvb_reported_length (tvb); offset++)
1427                 {
1428                         peek = tvb_get_guint8 (tvb, offset);
1429                         if (peek == '=')
1430                         {
1431                                 variableEnd = offset;
1432                                 valueStart = offset+1;
1433                         }
1434                         else if (peek == '&')
1435                         {
1436                                 if (variableEnd > 0)
1437                                 {
1438                                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
1439                                 }
1440                                 variableStart = offset+1;
1441                                 variableEnd = 0;
1442                                 valueStart = 0;
1443                                 valueEnd = 0;
1444                         }
1445                 }
1446
1447                 /* See if there's outstanding data */
1448                 if (variableEnd > 0)
1449                 {
1450                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
1451                 }
1452         }
1453 }
1454
1455 static void
1456 add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
1457 {
1458         int variableLength = variableEnd-variableStart;
1459         int valueLength = 0;
1460         char *variableBuffer;
1461         char *valueBuffer;
1462
1463         variableBuffer = g_malloc (variableLength+1);
1464         strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength);
1465         variableBuffer[variableLength] = 0;
1466
1467         if (valueEnd < valueStart)
1468         {
1469                 valueBuffer = g_malloc (1);
1470                 valueBuffer[0] = 0;
1471                 valueEnd = valueStart;
1472         }
1473         else
1474         {
1475                 valueLength = valueEnd-valueStart;
1476                 valueBuffer = g_malloc (valueLength+1);
1477                 strncpy (valueBuffer, tvb_get_ptr (tvb, valueStart, valueLength), valueLength);
1478                 valueBuffer[valueLength] = 0;
1479         }
1480
1481         /* Check for variables with no value */
1482         if (valueStart >= tvb_reported_length (tvb))
1483         {
1484                 valueStart = tvb_reported_length (tvb);
1485                 valueEnd = valueStart;
1486         }
1487         valueLength = valueEnd-valueStart;
1488
1489         proto_tree_add_text (tree, tvb, variableStart, valueEnd-variableStart, "%s: %s", variableBuffer, valueBuffer);
1490
1491         g_free (variableBuffer);
1492         g_free (valueBuffer);
1493 }
1494
1495 /* Register the protocol with Ethereal */
1496 void
1497 proto_register_wsp(void)
1498 {                 
1499
1500 /* Setup list of header fields */
1501         static hf_register_info hf[] = {
1502                 { &hf_wsp_header_tid,
1503                         {       "Transmission ID",           
1504                                 "wsp.TID",
1505                                  FT_UINT8, BASE_HEX, NULL, 0x00,
1506                                 "Transmission ID" 
1507                         }
1508                 },
1509                 { &hf_wsp_header_pdu_type,
1510                         {       "PDU Type",           
1511                                 "wsp.pdu_type",
1512                                  FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
1513                                 "PDU Type" 
1514                         }
1515                 },
1516                 { &hf_wsp_version_major,
1517                         {       "Version (Major)",           
1518                                 "wsp.version.major",
1519                                  FT_UINT8, BASE_DEC, NULL, 0xF0,
1520                                 "Version (Major)" 
1521                         }
1522                 },
1523                 { &hf_wsp_version_minor,
1524                         {       "Version (Minor)",           
1525                                 "wsp.version.minor",
1526                                  FT_UINT8, BASE_DEC, NULL, 0x0F,
1527                                 "Version (Minor)" 
1528                         }
1529                 },
1530                 { &hf_wsp_capability_length,
1531                         {       "Capability Length",           
1532                                 "wsp.capability.length",
1533                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1534                                 "Capability Length" 
1535                         }
1536                 },
1537                 { &hf_wsp_header_length,
1538                         {       "Headers Length",           
1539                                 "wsp.headers_length",
1540                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1541                                 "Headers Length" 
1542                         }
1543                 },
1544                 { &hf_wsp_capabilities_section,
1545                         {       "Capabilities",           
1546                                 "wsp.capabilities",
1547                                  FT_NONE, BASE_DEC, NULL, 0x00,
1548                                 "Capabilities" 
1549                         }
1550                 },
1551                 { &hf_wsp_headers_section,
1552                         {       "Headers",           
1553                                 "wsp.headers",
1554                                  FT_NONE, BASE_DEC, NULL, 0x00,
1555                                 "Headers" 
1556                         }
1557                 },
1558                 { &hf_wsp_header,
1559                         {       "Header",           
1560                                 "wsp.headers.header",
1561                                  FT_NONE, BASE_DEC, NULL, 0x00,
1562                                 "Header" 
1563                         }
1564                 },
1565                 { &hf_wsp_header_uri_len,
1566                         {       "URI Length",           
1567                                 "wsp.uri_length",
1568                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1569                                 "URI Length" 
1570                         }
1571                 },
1572                 { &hf_wsp_header_uri,
1573                         {       "URI",           
1574                                 "wsp.uri",
1575                                  FT_STRING, BASE_NONE, NULL, 0x00,
1576                                 "URI" 
1577                         }
1578                 },
1579                 { &hf_wsp_server_session_id,
1580                         {       "Server Session ID",           
1581                                 "wsp.server.session_id",
1582                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1583                                 "Server Session ID" 
1584                         }
1585                 },
1586                 { &hf_wsp_header_status,
1587                         {       "Status",           
1588                                 "wsp.reply.status",
1589                                  FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
1590                                 "Status" 
1591                         }
1592                 },
1593                 { &hf_wsp_content_type,
1594                         {       "Content Type",           
1595                                 "wsp.content_type.type",
1596                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
1597                                 "Content Type" 
1598                         }
1599                 },
1600                 { &hf_wsp_parameter_well_known_charset,
1601                         {       "Charset",           
1602                                 "wsp.content_type.parameter.charset",
1603                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
1604                                 "Charset" 
1605                         }
1606                 },
1607                 { &hf_wsp_reply_data,
1608                         {       "Data",           
1609                                 "wsp.reply.data",
1610                                  FT_NONE, BASE_NONE, NULL, 0x00,
1611                                 "Data" 
1612                         }
1613                 },
1614                 { &hf_wsp_header_accept,
1615                         {       "Accept",           
1616                                 "wsp.header.accept",
1617                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1618                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
1619                                 "Accept" 
1620                         }
1621                 },
1622                 { &hf_wsp_header_accept_str,
1623                         {       "Accept",           
1624                                 "wsp.header.accept.string",
1625                                  FT_STRING, BASE_NONE, NULL, 0x00,
1626                                 "Accept" 
1627                         }
1628                 },
1629                 { &hf_wsp_header_accept_charset,
1630                         {       "Accept-Charset",           
1631                                 "wsp.header.accept_charset",
1632                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
1633                                 "Accept-Charset" 
1634                         }
1635                 },
1636                 { &hf_wsp_header_accept_charset_str,
1637                         {       "Accept-Charset",           
1638                                 "wsp.header.accept_charset.string",
1639                                  FT_STRING, BASE_NONE, NULL, 0x00,
1640                                 "Accept-Charset" 
1641                         }
1642                 },
1643                 { &hf_wsp_header_accept_language,
1644                         {       "Accept-Language",           
1645                                 "wsp.header.accept_language",
1646                                  FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
1647                                 "Accept-Language" 
1648                         }
1649                 },
1650                 { &hf_wsp_header_accept_language_str,
1651                         {       "Accept-Language",           
1652                                 "wsp.header.accept_language.string",
1653                                  FT_STRING, BASE_NONE, NULL, 0x00,
1654                                 "Accept-Language" 
1655                         }
1656                 },
1657                 { &hf_wsp_header_accept_ranges,
1658                         {       "Accept-Ranges",           
1659                                 "wsp.header.accept_ranges",
1660                                  FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
1661                                 "Accept-Ranges" 
1662                         }
1663                 },
1664                 { &hf_wsp_header_age,
1665                         {       "Age",           
1666                                 "wsp.header.age",
1667                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1668                                 "Age" 
1669                         }
1670                 },
1671                 { &hf_wsp_header_cache_control,
1672                         {       "Cache-Control",           
1673                                 "wsp.header.cache_control",
1674                                  FT_UINT8, BASE_HEX, VALS ( vals_cache_control ), 0x00,
1675                                 "Cache-Control" 
1676                         }
1677                 },
1678                 { &hf_wsp_header_content_length,
1679                         {       "Content-Length",           
1680                                 "wsp.header.content_length",
1681                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1682                                 "Content-Length" 
1683                         }
1684                 },
1685                 { &hf_wsp_header_date,
1686                         {       "Date",           
1687                                 "wsp.header.date",
1688                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1689                                 "Date" 
1690                         }
1691                 },
1692                 { &hf_wsp_header_etag,
1693                         {       "Etag",           
1694                                 "wsp.header.etag",
1695                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1696                                  FT_STRING, BASE_NONE, NULL, 0x00,
1697                                 "Etag" 
1698                         }
1699                 },
1700                 { &hf_wsp_header_expires,
1701                         {       "Expires",           
1702                                 "wsp.header.expires",
1703                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1704                                 "Expires" 
1705                         }
1706                 },
1707                 { &hf_wsp_header_last_modified,
1708                         {       "Last-Modified",           
1709                                 "wsp.header.last_modified",
1710                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1711                                 "Last-Modified" 
1712                         }
1713                 },
1714                 { &hf_wsp_header_location,
1715                         {       "Location",           
1716                                 "wsp.header.location",
1717                                  FT_STRING, BASE_NONE, NULL, 0x00,
1718                                 "Location" 
1719                         }
1720                 },
1721                 { &hf_wsp_header_if_modified_since,
1722                         {       "If-Modified-Since",           
1723                                 "wsp.header.if_modified_since",
1724                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1725                                 "If-Modified-Since" 
1726                         }
1727                 },
1728                 { &hf_wsp_header_server,
1729                         {       "Server",           
1730                                 "wsp.header.server",
1731                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1732                                  FT_STRING, BASE_NONE, NULL, 0x00,
1733                                 "Server" 
1734                         }
1735                 },
1736                 { &hf_wsp_header_transfer_encoding,
1737                         {       "Transfer Encoding",           
1738                                 "wsp.header.transfer_enc",
1739                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1740                                  FT_UINT8, BASE_HEX, VALS ( vals_transfer_encoding ), 0x00,
1741                                 "Transfer Encoding" 
1742                         }
1743                 },
1744                 { &hf_wsp_header_transfer_encoding_str,
1745                         {       "Transfer Encoding",           
1746                                 "wsp.header.transfer_enc_str",
1747                                  FT_STRING, BASE_NONE, NULL, 0x00,
1748                                 "Transfer Encoding" 
1749                         }
1750                 },
1751                 { &hf_wsp_header_user_agent,
1752                         {       "User-Agent",           
1753                                 "wsp.header.user_agent",
1754                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1755                                  FT_STRING, BASE_NONE, NULL, 0x00,
1756                                 "User-Agent" 
1757                         }
1758                 },
1759                 { &hf_wsp_header_via,
1760                         {       "Via",           
1761                                 "wsp.header.via",
1762                                  FT_STRING, BASE_NONE, NULL, 0x00,
1763                                 "Via" 
1764                         }
1765                 },
1766                 { &hf_wsp_header_application_header,
1767                         {       "Application Header",           
1768                                 "wsp.header.application_header",
1769                                  FT_STRING, BASE_NONE, NULL, 0x00,
1770                                 "Application Header" 
1771                         }
1772                 },
1773                 { &hf_wsp_header_application_value,
1774                         {       "Application Header Value",           
1775                                 "wsp.header.application_header.value",
1776                                  FT_STRING, BASE_NONE, NULL, 0x00,
1777                                 "Application Header Value" 
1778                         }
1779                 },
1780                 { &hf_wsp_header_x_wap_tod,
1781                         {       "X-WAP.TOD",           
1782                                 "wsp.header.x_wap_tod",
1783                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1784                                 "X-WAP.TOD" 
1785                         }
1786                 },
1787                 { &hf_wsp_post_data,
1788                         {       "Post Data",           
1789                                 "wsp.post.data",
1790                                  FT_NONE, BASE_NONE, NULL, 0x00,
1791                                 "Post Data" 
1792                         }
1793                 },
1794         };
1795         
1796 /* Setup protocol subtree array */
1797         static gint *ett[] = {
1798                 &ett_wsp,
1799                 &ett_header,
1800                 &ett_headers,
1801                 &ett_capabilities,
1802                 &ett_content_type,
1803         };
1804
1805 /* Register the protocol name and description */
1806         proto_wsp = proto_register_protocol(
1807                 "Wireless Session Protocol",    /* protocol name for use by ethereal */ 
1808                 "WSP",                          /* short version of name */
1809                 "wap-wsp"                       /* Abbreviated protocol name, should Match IANA 
1810                                                     < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
1811                                                   */
1812         );
1813
1814 /* Required function calls to register the header fields and subtrees used  */
1815         proto_register_field_array(proto_wsp, hf, array_length(hf));
1816         proto_register_subtree_array(ett, array_length(ett));
1817
1818         register_dissector("wsp", dissect_wsp, proto_wsp);
1819 };
1820
1821 void
1822 proto_reg_handoff_wsp(void)
1823 {
1824         /*
1825          * Get a handle for the WMLC dissector
1826          */
1827         wmlc_handle = find_dissector("wmlc");   /* Coming soon :) */
1828
1829         /* Only connection-less WSP has no previous handler */
1830         dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp, proto_wsp);
1831
1832         /* This dissector is also called from the WTP and WTLS dissectors */
1833 }