Remove more "CHECK_DISPLAY_AS_DATA()" calls and "pinfo->current_proto ="
[obnox/wireshark/wip.git] / packet-wsp.c
1 /* packet-wsp.c (c) 2000 Neil Hunter
2  * Based on original work by Ben Fowler
3  *
4  * Routines to dissect WSP component of WAP traffic.
5  * 
6  * $Id: packet-wsp.c,v 1.12 2001/01/22 08:03:46 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Didier Jorand
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #ifdef NEED_SNPRINTF_H
43 # ifdef HAVE_STDARG_H
44 #  include <stdarg.h>
45 # else
46 #  include <varargs.h>
47 # endif
48 # include "snprintf.h"
49 #endif
50
51 #include <string.h>
52 #include <glib.h>
53 #include "packet.h"
54 #include "packet-wap.h"
55 #include "packet-wsp.h"
56
57 /* File scoped variables for the protocol and registered fields */
58 static int proto_wsp                                                    = HF_EMPTY;
59
60 /* These fields used by fixed part of header */
61 static int hf_wsp_header_tid                                    = HF_EMPTY;
62 static int hf_wsp_header_pdu_type                               = HF_EMPTY;
63 static int hf_wsp_version_major                                 = HF_EMPTY;
64 static int hf_wsp_version_minor                                 = HF_EMPTY;
65 static int hf_wsp_capability_length                             = HF_EMPTY;
66 static int hf_wsp_capabilities_section                  = HF_EMPTY;
67 static int hf_wsp_header_uri_len                                = HF_EMPTY;
68 static int hf_wsp_header_uri                                    = HF_EMPTY;
69 static int hf_wsp_server_session_id                             = HF_EMPTY;
70 static int hf_wsp_header_status                                 = HF_EMPTY;
71 static int hf_wsp_header_length                                 = HF_EMPTY;
72 static int hf_wsp_headers_section                               = HF_EMPTY;
73 static int hf_wsp_header                                                = HF_EMPTY;
74 static int hf_wsp_content_type                                  = HF_EMPTY;
75 static int hf_wsp_parameter_well_known_charset  = HF_EMPTY;
76 static int hf_wsp_reply_data                                    = HF_EMPTY;
77 static int hf_wsp_post_data                                             = HF_EMPTY;
78
79 static int hf_wsp_header_accept                                 = HF_EMPTY;
80 static int hf_wsp_header_accept_str                             = HF_EMPTY;
81 static int hf_wsp_header_accept_charset                 = HF_EMPTY;
82 static int hf_wsp_header_accept_language                = HF_EMPTY;
83 static int hf_wsp_header_accept_ranges                  = HF_EMPTY;
84 static int hf_wsp_header_cache_control                  = HF_EMPTY;
85 static int hf_wsp_header_content_length                 = HF_EMPTY;
86 static int hf_wsp_header_age                                    = HF_EMPTY;
87 static int hf_wsp_header_date                                   = HF_EMPTY;
88 static int hf_wsp_header_etag                                   = HF_EMPTY;
89 static int hf_wsp_header_expires                                = HF_EMPTY;
90 static int hf_wsp_header_last_modified                  = HF_EMPTY;
91 static int hf_wsp_header_location                               = HF_EMPTY;
92 static int hf_wsp_header_if_modified_since              = HF_EMPTY;
93 static int hf_wsp_header_server                                 = HF_EMPTY;
94 static int hf_wsp_header_user_agent                             = HF_EMPTY;
95 static int hf_wsp_header_application_header             = HF_EMPTY;
96 static int hf_wsp_header_application_value              = HF_EMPTY;
97 static int hf_wsp_header_x_wap_tod                              = HF_EMPTY;
98
99 /* Initialize the subtree pointers */
100 static gint ett_wsp                                                     = ETT_EMPTY;
101 static gint ett_header                                                  = ETT_EMPTY;
102 static gint ett_headers                                                 = ETT_EMPTY;
103 static gint ett_capabilities                                    = ETT_EMPTY;
104 static gint ett_content_type                                    = ETT_EMPTY;
105
106 static const value_string vals_pdu_type[] = {
107         { 0x00, "Reserved" },
108         { 0x01, "Connect" },
109         { 0x02, "ConnectReply" },
110         { 0x03, "Redirect" },
111         { 0x04, "Reply" },
112         { 0x05, "Disconnect" },
113         { 0x06, "Push" },
114         { 0x07, "ConfirmedPush" },
115         { 0x08, "Suspend" },
116         { 0x09, "Resume" },
117
118         /* 0x10 - 0x3F Unassigned */
119
120         { 0x40, "Get" },
121         { 0x41, "Options" },
122         { 0x42, "Head" },
123         { 0x43, "Delete" },
124         { 0x44, "Trace" },
125
126         /* 0x45 - 0x4F Unassigned (Get PDU) */
127         /* 0x50 - 0x5F Extended method (Get PDU) */
128
129         { 0x60, "Post" },
130         { 0x61, "Put" },
131
132         /* 0x62 - 0x6F Unassigned (Post PDU) */
133         /* 0x70 - 0x7F Extended method (Post PDU) */
134         /* 0x80 - 0xFF Reserved */
135
136         { 0x00, NULL }
137
138 };
139
140 static const value_string vals_status[] = {
141         /* 0x00 - 0x0F Reserved */
142
143         { 0x10, "Continue" },
144         { 0x11, "Switching Protocols" },
145
146         { 0x20, "OK" },
147         { 0x21, "Created" },
148         { 0x22, "Accepted" },
149         { 0x23, "Non-Authoritative Information" },
150         { 0x24, "No Content" },
151         { 0x25, "Reset Content" },
152         { 0x26, "Partial Content" },
153
154         { 0x30, "Multiple Choices" },
155         { 0x31, "Moved Permanently" },
156         { 0x32, "Moved Temporarily" },
157         { 0x33, "See Other" },
158         { 0x34, "Not Modified" },
159         { 0x35, "Use Proxy" },
160
161         { 0x40, "Bad Request" },
162         { 0x41, "Unauthorised" },
163         { 0x42, "Payment Required" },
164         { 0x43, "Forbidden" },
165         { 0x44, "Not Found" },
166         { 0x45, "Method Not Allowed" },
167         { 0x46, "Not Acceptable" },
168         { 0x47, "Proxy Authentication Required" },
169         { 0x48, "Request Timeout" },
170         { 0x49, "Conflict" },
171         { 0x4A, "Gone" },
172         { 0x4B, "Length Required" },
173         { 0x4C, "Precondition Failed" },
174         { 0x4D, "Request Entity Too Large" },
175         { 0x4E, "Request-URI Too Large" },
176         { 0x4F, "Unsupported Media Type" },
177
178         { 0x60, "Internal Server Error" },
179         { 0x61, "Not Implemented" },
180         { 0x62, "Bad Gateway" },
181         { 0x63, "Service Unavailable" },
182         { 0x64, "Gateway Timeout" },
183         { 0x65, "HTTP Version Not Supported" },
184         { 0x00, NULL }
185 };
186
187 static const value_string vals_content_types[] = {
188         { 0x00, "*/*" },
189         { 0x01, "text/*" },
190         { 0x02, "text/html" },
191         { 0x03, "text/plain" },
192         { 0x04, "text/x-hdml" },
193         { 0x05, "text/x-ttml" },
194         { 0x06, "text/x-vCalendar" },
195         { 0x07, "text/x-vCard" },
196         { 0x08, "text/vnd.wap.wml" },
197         { 0x09, "text/vnd.wap.wmlscript" },
198         { 0x0A, "text/vnd.wap.channel" },
199         { 0x0B, "Multipart/*" },
200         { 0x0C, "Multipart/mixed" },
201         { 0x0D, "Multipart/form-data" },
202         { 0x0E, "Multipart/byteranges" },
203         { 0x0F, "Multipart/alternative" },
204         { 0x10, "application/*" },
205         { 0x11, "application/java-vm" },
206         { 0x12, "application/x-www-form-urlencoded" },
207         { 0x13, "application/x-hdmlc" },
208         { 0x14, "application/vnd.wap.wmlc" },
209         { 0x15, "application/vnd.wap.wmlscriptc" },
210         { 0x16, "application/vnd.wap.channelc" },
211         { 0x17, "application/vnd.wap.uaprof" },
212         { 0x18, "application/vnd.wap.wtls-ca-certificate" },
213         { 0x19, "application/vnd.wap.wtls-user-certificate" },
214         { 0x1A, "application/x-x509-ca-cert" },
215         { 0x1B, "application/x-x509-user-cert" },
216         { 0x1C, "image/*" },
217         { 0x1D, "image/gif" },
218         { 0x1E, "image/jpeg" },
219         { 0x1F, "image/tiff" },
220         { 0x20, "image/png" },
221         { 0x21, "image/vnd.wap.wbmp" },
222         { 0x22, "application/vnd.wap.multipart.*" },
223         { 0x23, "application/vnd.wap.multipart.mixed" },
224         { 0x24, "application/vnd.wap.multipart.form-data" },
225         { 0x25, "application/vnd.wap.multipart.byteranges" },
226         { 0x26, "application/vnd.wap.multipart.alternative" },
227         { 0x27, "application/xml" },
228         { 0x28, "text/xml" },
229         { 0x29, "application/vnd.wap.wbxml" },
230         { 0x2A, "application/x-x968-cross-cert" },
231         { 0x2B, "application/x-x968-ca-cert" },
232         { 0x2C, "application/x-x968-user-cert" },
233         { 0x2D, "text/vnd.wap.si" },
234         { 0x2E, "application/vnd.wap.sic" },
235         { 0x2F, "text/vnd.wap.sl" },
236         { 0x30, "application/vnd.wap.slc" },
237         { 0x31, "text/vnd.wap.co" },
238         { 0x32, "application/vnd.wap.coc" },
239         { 0x33, "application/vnd.wap.multipart.related" },
240         { 0x34, "application/vnd.wap.sia" },
241         { 0x00, NULL }
242 };
243
244 static const value_string vals_character_sets[] = {
245         { 0x0003, "us-ascii" },
246         { 0x0004, "iso-8859-1" },
247         { 0x0005, "iso-8859-2" },
248         { 0x0006, "iso-8859-3" },
249         { 0x0007, "iso-8859-4" },
250         { 0x0008, "iso-8859-5" },
251         { 0x0009, "iso-8859-6" },
252         { 0x000A, "iso-8859-7" },
253         { 0x000B, "iso-8859-8" },
254         { 0x000C, "iso-8859-9" },
255         { 0x0011, "shift_JIS" },
256         { 0x006A, "utf-8" },
257         { 0x03E8, "iso-10646-ucs-2" },
258         { 0x07EA, "big5" },
259         { 0x00, NULL }
260 };
261
262 static const value_string vals_languages[] = {
263         { 0x19, "English (en)" },
264         { 0x00, NULL }
265 };
266
267 static const value_string vals_accept_ranges[] = {
268         { 0x80, "None" },
269         { 0x81, "Bytes" },
270         { 0x00, NULL }
271 };
272
273 static const value_string vals_cache_control[] = {
274         { 0x80, "No-cache" },
275         { 0x81, "No-store" },
276         { 0x82, "Max-age" },
277         { 0x83, "Max-stale" },
278         { 0x84, "Min-fresh" },
279         { 0x85, "Only-if-cached" },
280         { 0x86, "Public" },
281         { 0x87, "Private" },
282         { 0x88, "No-transform" },
283         { 0x89, "Must-revalidate" },
284         { 0x8A, "Proxy-revalidate" },
285         { 0x00, NULL }
286 };
287
288 /*
289  * Windows appears to define DELETE.
290  */
291 #ifdef DELETE
292 #undef DELETE
293 #endif
294
295 enum {
296         RESERVED                = 0x00,
297         CONNECT                 = 0x01,
298         CONNECTREPLY    = 0x02,
299         REDIRECT                = 0x03,                 /* No sample data */
300         REPLY                   = 0x04,
301         DISCONNECT              = 0x05,
302         PUSH                    = 0x06,                 /* No sample data */
303         CONFIRMEDPUSH   = 0x07,                 /* No sample data */
304         SUSPEND                 = 0x08,                 /* No sample data */
305         RESUME                  = 0x09,                 /* No sample data */
306
307         GET                             = 0x40,
308         OPTIONS                 = 0x41,                 /* No sample data */
309         HEAD                    = 0x42,                 /* No sample data */
310         DELETE                  = 0x43,                 /* No sample data */
311         TRACE                   = 0x44,                 /* No sample data */
312
313         POST                    = 0x60,
314         PUT                             = 0x61,                 /* No sample data */
315 };
316
317 void add_uri (proto_tree *, tvbuff_t *, guint, guint);
318 void add_headers (proto_tree *, tvbuff_t *);
319 void add_header (proto_tree *, tvbuff_t *, tvbuff_t *);
320 guint get_value_length (tvbuff_t *, guint, guint *);
321 guint add_content_type (proto_tree *, tvbuff_t *, guint, guint *);
322 guint add_parameter (proto_tree *, tvbuff_t *, guint);
323 guint add_parameter_charset (proto_tree *, tvbuff_t *, guint, guint);
324 void add_post_data (proto_tree *, tvbuff_t *, guint);
325 void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
326
327 /* 
328  * Accessor to retrieve variable length int as used in WAP protocol.
329  * The value is encoded in the lower 7 bits. If the top bit is set, then the
330  * value continues into the next byte.
331  * The octetCount parameter holds the number of bytes read in order to return
332  * the final value. Can be pre-initialised to start at offset+count.
333 */
334 guint
335 tvb_get_guintvar (tvbuff_t *tvb, guint offset, guint *octetCount)
336 {
337         guint value = 0;
338         guint octet;
339         guint counter = 0;
340         char cont = 1;
341         
342         if (octetCount != NULL)
343         {
344 #ifdef DEBUG
345                 fprintf (stderr, "dissect_wsp: Starting tvb_get_guintvar at offset %d, count=NULL\n", offset);
346 #endif
347         }
348         else
349         {
350 #ifdef DEBUG
351                 fprintf (stderr, "dissect_wsp: Starting tvb_get_guintvar at offset %d, count=%d\n", offset, *octetCount);
352 #endif
353                 counter = *octetCount;
354         }
355
356         while (cont != 0)
357         {
358                 value<<=7;      /* Value only exists in 7 of the 8 bits */
359                 octet = tvb_get_guint8 (tvb, offset+counter);
360                 counter++;
361                 value += (octet & 0x7F);
362                 cont = (octet & 0x80);
363 #ifdef DEBUG
364                 fprintf (stderr, "dissect_wsp: octet is %d (0x%02x), count=%d, value=%d, cont=%d\n", octet, octet, counter, value, cont);
365 #endif
366         }
367
368         if (octetCount != NULL)
369         {
370                 *octetCount = counter;
371 #ifdef DEBUG
372                 fprintf (stderr, "dissect_wsp: Leaving tvb_get_guintvar count=%d\n", *octetCount);
373 #endif
374         }
375
376         return (value);
377 }
378
379 /* Code to actually dissect the packets */
380 static void
381 dissect_wsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
382 {
383         frame_data *fdata = pinfo->fd;
384         int offset = 0;
385
386         guint8 pdut;
387         guint count = 0;
388         guint value = 0;
389         guint uriLength = 0;
390         guint uriStart = 0;
391         guint capabilityLength = 0;
392         guint capabilityStart = 0;
393         guint headersLength = 0;
394         guint headerLength = 0;
395         guint headerStart = 0;
396         guint nextOffset = 0;
397         guint contentTypeStart = 0;
398         guint contentType = 0;
399         tvbuff_t *tmp_tvb;
400
401 /* Set up structures we will need to add the protocol subtree and manage it */
402         proto_item *ti;
403         proto_tree *wsp_tree;
404 /*      proto_tree *wsp_header_fixed; */
405         proto_tree *wsp_capabilities;
406         
407 /* This field shows up as the "Info" column in the display; you should make
408    it, if possible, summarize what's in the packet, so that a user looking
409    at the list of packets can tell what type of packet it is. */
410     
411         /* Display protocol type depending on the port */
412         if (check_col(fdata, COL_PROTOCOL)) 
413         {
414                 switch ( pinfo->match_port )
415                 {
416                         case UDP_PORT_WSP:
417                                 col_set_str(fdata, COL_PROTOCOL, "WSP" );
418                                 break;
419                         case UDP_PORT_WTLS_WSP:
420                                 col_set_str(fdata, COL_PROTOCOL, "WTLS+WSP" );
421                                 break;
422                 }
423         }
424         if (check_col(fdata, COL_INFO)) {
425                 col_clear(fdata, COL_INFO);
426         };
427
428         /* Connection-less mode has a TID first */
429         if ((pinfo->match_port == UDP_PORT_WSP) || (pinfo->match_port == UDP_PORT_WTLS_WSP))
430         {
431                 offset++;
432         };
433
434         /* Find the PDU type */
435         pdut = tvb_get_guint8 (tvb, offset);
436
437         /* Develop the string to put in the Info column */
438         if (check_col(fdata, COL_INFO)) {
439                 col_add_fstr(fdata, COL_INFO, "WSP %s",
440                         val_to_str (pdut, vals_pdu_type, "Unknown PDU type (0x%02x)"));
441         };
442
443 /* In the interest of speed, if "tree" is NULL, don't do any work not
444    necessary to generate protocol tree items. */
445         if (tree) {
446                 ti = proto_tree_add_item(tree, proto_wsp, tvb, 0,
447                     tvb_length(tvb), bo_little_endian);
448                 wsp_tree = proto_item_add_subtree(ti, ett_wsp);
449
450 /* Code to process the packet goes here */
451 /*
452                         wsp_header_fixed = proto_item_add_subtree(
453                                         ti, 
454                                         ett_header 
455                                 );
456 */
457
458                         /* Add common items: only TID and PDU Type */
459
460                         /* TID Field is always first (if it exists) */
461                         if ((pinfo->match_port == UDP_PORT_WSP) || (pinfo->match_port == UDP_PORT_WTLS_WSP))
462                         {
463                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_tid,tvb,0,1,bo_little_endian);
464                         }
465
466                         ti = proto_tree_add_item(
467                                         wsp_tree,               /* tree */
468                                         hf_wsp_header_pdu_type,         /* id */
469                                         tvb, 
470                                         offset++,                       /* start of high light */
471                                         1,                              /* length of high light */
472                                         bo_little_endian                                /* value */
473                              );
474
475                         switch (pdut)
476                         {
477                                 case CONNECT:
478                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
479                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
480                                         offset++;
481                                         capabilityStart = offset;
482                                         capabilityLength = tvb_get_guintvar (tvb, offset, &count);
483                                         offset += count;
484                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
485
486                                         headerStart = offset;
487                                         headerLength = tvb_get_guintvar (tvb, offset, &count);
488                                         offset += count;
489                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
490                                         if (capabilityLength > 0)
491                                         {
492                                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_capabilities_section,tvb,offset,capabilityLength,bo_little_endian);
493                                                 wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
494                                                 offset += capabilityLength;
495                                         }
496
497                                         if (headerLength > 0)
498                                         {
499                                                 tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
500                                                 add_headers (wsp_tree, tmp_tvb);
501                                         }
502
503                                         break;
504
505                                 case CONNECTREPLY:
506                                         value = tvb_get_guintvar (tvb, offset, &count);
507                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
508                                         offset += count;
509
510                                         capabilityStart = offset;
511                                         capabilityLength = tvb_get_guintvar (tvb, offset, &count);
512                                         offset += count;
513                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
514
515                                         headerStart = offset;
516                                         headerLength = tvb_get_guintvar (tvb, offset, &count);
517                                         offset += count;
518                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,bo_little_endian);
519                                         if (capabilityLength > 0)
520                                         {
521                                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_capabilities_section,tvb,offset,capabilityLength,bo_little_endian);
522                                                 wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
523                                                 offset += capabilityLength;
524                                         }
525
526                                         if (headerLength > 0)
527                                         {
528
529                                                 /*
530                                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_headers_section,tvb,offset,headerLength,bo_little_endian);
531                                                 wsp_headers = proto_item_add_subtree( ti, ett_headers );
532                                                 */
533                                                 tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
534                                                 add_headers (wsp_tree, tmp_tvb);
535                                         }
536
537                                         break;
538
539                                 case DISCONNECT:
540                                         value = tvb_get_guintvar (tvb, offset, &count);
541                                         ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
542                                         break;
543
544                                 case GET:
545                                         /* Length of URI and size of URILen field */
546                                         value = tvb_get_guintvar (tvb, offset, &count);
547                                         nextOffset = offset + count;
548                                         add_uri (wsp_tree, tvb, offset, nextOffset);
549                                         offset += (value+1);
550                                         tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
551                                         add_headers (wsp_tree, tmp_tvb);
552                                         break;
553
554                                 case POST:
555                                         uriStart = offset;
556                                         uriLength = tvb_get_guintvar (tvb, offset, &count);
557                                         headerStart = uriStart+count;
558                                         headersLength = tvb_get_guintvar (tvb, headerStart, &count);
559                                         offset = headerStart + count;
560
561                                         add_uri (wsp_tree, tvb, uriStart, offset);
562                                         offset += uriLength;
563
564                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,bo_little_endian);
565
566                                         contentTypeStart = offset;
567                                         nextOffset = add_content_type (wsp_tree, tvb, offset, &contentType);
568
569                                         /* Add headers subtree that will hold the headers fields */
570                                         /* Runs from nextOffset for value-(length of content-type field)*/
571                                         headerLength = headersLength-(nextOffset-contentTypeStart);
572                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
573                                         add_headers (wsp_tree, tmp_tvb);
574
575                                         /* TODO: Post DATA */
576                                         /* Runs from start of headers+headerLength to END_OF_FRAME */
577                                         offset = nextOffset+headerLength;
578                                         tmp_tvb = tvb_new_subset (tvb, offset, tvb_reported_length (tvb)-offset, tvb_reported_length (tvb)-offset);
579                                         add_post_data (wsp_tree, tmp_tvb, contentType);
580                                         break;
581
582                                 case REPLY:
583                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
584                                         value = tvb_get_guintvar (tvb, offset+1, &count);
585                                         nextOffset = offset + 1 + count;
586                                         ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,bo_little_endian);
587
588                                         contentTypeStart = nextOffset;
589                                         nextOffset = add_content_type (wsp_tree, tvb, nextOffset, &contentType);
590
591                                         /* Add headers subtree that will hold the headers fields */
592                                         /* Runs from nextOffset for value-(length of content-type field)*/
593                                         headerLength = value-(nextOffset-contentTypeStart);
594                                         tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
595                                         add_headers (wsp_tree, tmp_tvb);
596                                         offset += count+value+1;
597
598                                         /* TODO: Data - decode WMLC */
599                                         /* Runs from offset+1+count+value+1 to END_OF_FRAME */
600                                         if (offset < tvb_reported_length (tvb))
601                                         {
602                                                 ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,END_OF_FRAME,bo_little_endian);
603                                         }
604                                         break;
605                         }
606         }
607 }
608
609 void
610 add_uri (proto_tree *tree, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
611 {
612         proto_item *ti;
613         guint8 terminator = 0;
614         char *newBuffer;
615
616         guint count = 0;
617         guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
618
619         ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
620
621         /* If string doesn't end with a 0x00, we need to add one to be on the safe side */
622         terminator = tvb_get_guint8 (tvb, URIOffset+uriLen-1);
623         if (terminator != 0)
624         {
625                 newBuffer = g_malloc (uriLen+1);
626                 strncpy (newBuffer, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
627                 newBuffer[uriLen] = 0;
628                 ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer);
629                 g_free (newBuffer);
630         }
631         else
632         {
633                 ti = proto_tree_add_item (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,bo_little_endian);
634         }
635 }
636
637 void
638 add_headers (proto_tree *tree, tvbuff_t *tvb)
639 {
640         proto_item *ti;
641         proto_tree *wsp_headers;
642         guint offset = 0;
643         guint headersLen = tvb_reported_length (tvb);
644         guint8 headerStart = 0;
645         guint peek = 0;
646         tvbuff_t *header_buff;
647         tvbuff_t *value_buff;
648         guint count = 0;
649         guint valueStart = 0;
650         guint valueEnd = 0;
651
652 #ifdef DEBUG
653         fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, headersLen);
654 #endif
655
656         /* End of buffer */
657         if (headersLen <= 0)
658         {
659                 return;
660         }
661
662 #ifdef DEBUG
663         fprintf (stderr, "dissect_wsp: Headers to process\n");
664 #endif
665
666         ti = proto_tree_add_item (tree, hf_wsp_headers_section,tvb,offset,headersLen,bo_little_endian);
667         wsp_headers = proto_item_add_subtree( ti, ett_headers );
668
669         /* Parse Headers */
670
671         while (offset < headersLen)
672         {
673                 /* Loop round each header */
674                 headerStart = offset;
675                 peek = tvb_get_guint8 (tvb, headerStart);
676
677                 if (peek < 32)          /* Short-cut shift delimeter */
678                 {
679                         fprintf (stderr, "dissect_wsp: header: short-cut shift %d (0x%02X)\n", peek, peek);
680                         offset++;
681                 }
682                 else if (peek == 0x7F)  /* Shift delimeter */
683                 {
684                         fprintf (stderr, "dissect_wsp: header: shift delimeter %d (0x%02X)\n", peek, peek);
685                         offset++;
686                 }
687                 else if (peek < 127)
688                 {
689 #ifdef DEBUG
690                         fprintf (stderr, "dissect_wsp: header: application-header start %d (0x%02X)\n", peek, peek);
691 #endif
692                         while (tvb_get_guint8 (tvb, offset++)) { /* Do nothing, just look for NULL */ }
693                 }
694                 else if (peek & 0x80)   /* Well-known header */
695                 {
696 #ifdef DEBUG
697                         fprintf (stderr, "dissect_wsp: header: well-known %d (0x%02X)\n", peek, peek);
698 #endif
699                         offset++;
700                 }
701
702                 /* Get value part of header */
703                 valueStart = offset;
704                 peek = tvb_get_guint8 (tvb, valueStart);
705                 if (peek <= 30)
706                 {
707 #ifdef DEBUG
708                         fprintf (stderr, "dissect_wsp: Looking for %d octets\n", peek);
709 #endif
710                         valueStart++;
711                         valueEnd = offset+1+peek;
712                         offset += (peek+1);
713                 }
714                 else if (peek == 31)
715                 {
716 #ifdef DEBUG
717                         fprintf (stderr, "dissect_wsp: Looking for uintvar octets\n");
718 #endif
719                         tvb_get_guintvar (tvb, valueStart, &count);
720                         valueEnd = offset+1+count;
721                         offset += (count+1);
722                 }
723                 else if (peek <= 127)
724                 {
725 #ifdef DEBUG
726                         fprintf (stderr, "dissect_wsp: Looking for NULL-terminated string\n");
727 #endif
728                         valueEnd = valueStart+1;
729                         while (tvb_get_guint8 (tvb, valueEnd++)) { /* Do nothing, just look for NULL */ }
730                         offset = valueEnd;
731                 }
732                 else
733                 {
734 #ifdef DEBUG
735                         fprintf (stderr, "dissect_wsp: Value is %d\n", (peek & 0x7F));
736 #endif
737                         valueEnd = offset+1;
738                         offset++;
739                 }
740 #ifdef DEBUG
741                 fprintf (stderr, "dissect_wsp: Creating value buffer from offset %d, size=%d\n", headerStart, (offset-headerStart));
742 #endif
743
744                 header_buff = tvb_new_subset (tvb, headerStart, (offset-headerStart), (offset-headerStart));
745                 value_buff = tvb_new_subset (tvb, valueStart, (valueEnd-valueStart), (valueEnd-valueStart));
746
747                 add_header (wsp_headers, header_buff, value_buff);
748         }
749 }
750
751 void
752 add_header (proto_tree *tree, tvbuff_t *header_buff, tvbuff_t *value_buff)
753 {
754         guint offset = 0;
755         guint8 headerType = 0;
756         proto_item *ti;
757         guint headerLen = tvb_reported_length (header_buff);
758         guint valueLen = tvb_reported_length (value_buff);
759         guint peek = 0;
760         struct timeval timeValue;
761         guint value = 0;
762
763         headerType = tvb_get_guint8 (header_buff, 0);
764         peek = tvb_get_guint8 (value_buff, 0);
765 #ifdef DEBUG
766         fprintf (stderr, "dissect_wsp: Got header 0x%02x\n", headerType);
767         fprintf (stderr, "dissect_wsp: First value octet is 0x%02x\n", peek);
768 #endif
769
770         if (headerType == 0x7F)
771         {
772         }
773         else if (headerType < 0x1F)
774         {
775         }
776         else if (headerType & 0x80)
777         {
778                 headerType = headerType & 0x7F;
779                 switch (headerType)
780                 {
781                 case 0x00:              /* Accept */
782                         if (peek & 0x80)
783                         {
784                                 proto_tree_add_uint (tree, hf_wsp_header_accept, header_buff, offset, headerLen, (peek & 0x7F));
785                         }
786                         else
787                         {
788                                 proto_tree_add_string (tree, hf_wsp_header_accept_str,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
789                         }
790                         break;
791
792                 case 0x01:              /* Accept-Charset */
793                         if (peek < 31)
794                         {
795                                 /* Peek contains the number of octets to follow */
796                                 switch (peek)
797                                 {
798                                         case 1:
799                                                 proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_guint8 (value_buff, 1) );
800                                                 break;
801                                         case 2:
802                                                 proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_ntohs (value_buff, 1) );
803                                                 break;
804                                         case 4:
805                                                 proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_ntohl (value_buff, 1) );
806                                                 break;
807                                         default:
808                                                 fprintf (stderr, "dissect_wsp: accept-charset size %d NYI\n", peek);
809                                 }
810                         }
811                         else if (peek & 0x80)
812                         {
813                                 proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, (peek & 0x7F) );
814                         }
815                         else
816                         {
817                                 fprintf (stderr, "dissect_wsp: Accept-Charset value %d (0x%02X) NYI\n", peek, peek);
818                         }
819                         break;
820
821                 case 0x03:              /* Accept-Language */
822                         proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, headerLen, (peek & 0x7F));
823                         break;
824
825                 case 0x04:              /* Accept-Ranges */
826                         if ((peek == 128) || (peek == 129))
827                         {
828                                 proto_tree_add_uint (tree, hf_wsp_header_accept_ranges, header_buff, offset, headerLen, peek);
829                         }
830                         else
831                         {
832                                 fprintf (stderr, "dissect_wsp: accept-ranges NYI\n");
833                         }
834                         
835                         break;
836
837                 case 0x05:              /* Age */
838                         switch (valueLen)
839                         {
840                                 case 1:
841                                         proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_guint8 (value_buff, 0));
842                                         break;
843                                 case 2:
844                                         proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntohs (value_buff, 0));
845                                         break;
846                                 case 3:
847                                         proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntoh24 (value_buff, 0));
848                                         break;
849                                 case 4:
850                                         proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntohl (value_buff, 0));
851                                         break;
852                         };
853                         break;
854
855                 case 0x08:              /* Cache-Control */
856                         if (peek & 0x80)
857                         {
858                                 if (valueLen == 1)      /* Well-known value */
859                                 {
860                                         proto_tree_add_uint (tree, hf_wsp_header_cache_control, header_buff, offset, headerLen, peek);
861                                 }
862                                 else
863                                 {
864                                         if ((peek == 0x82) || (peek == 0x83) || (peek == 0x84)) /* Delta seconds value to follow */
865                                         {
866                                                 value = tvb_get_guint8 (value_buff, 1);
867                                                 if (value & 0x80)
868                                                 {
869                                                         proto_tree_add_text (tree,
870                                                             header_buff, 0,
871                                                             headerLen,
872                                                             "Cache-Control: %s %d (0x%02X)",
873                                                             val_to_str (peek,
874                                                                 vals_cache_control,
875                                                                 "Unknown (0x%02x)"),
876                                                                 (value & 0x7F),
877                                                                 peek);
878                                                 }
879                                                 else
880                                                 {
881                                                         fprintf (stderr, "dissect_wsp: Cache-Control integer value Delta seconds NYI\n");
882                                                 }
883                                         }
884                                         else if ((peek == 0x80) || (peek == 0x87))      /* Fields to follow */
885                                         {
886                                                 fprintf (stderr, "dissect_wsp: Cache-Control field values NYI\n");
887                                         }
888                                         else
889                                         {
890                                                 fprintf (stderr, "dissect_wsp: Cache-Control cache extension NYI\n");
891                                         }
892                                 }
893                         }
894                         else
895                         {
896                                 fprintf (stderr, "dissect_wsp: Cache-Control cache extension NYI\n");
897                         }
898                         break;
899                                 
900                 case 0x0D:              /* Content-Length */
901                         if (peek & 0x80)
902                         {
903                                 proto_tree_add_uint (tree, hf_wsp_header_content_length, header_buff, offset, headerLen, (peek & 0x7F));
904                         }
905                         else
906                         {
907                                 fprintf (stderr, "dissect_wsp: Content-Length long-integer size NYI\n");
908                         }
909                         break;
910                                 
911                 case 0x12:              /* Date */
912                         timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
913                         ti = proto_tree_add_time (tree, hf_wsp_header_date, header_buff, offset, headerLen, &timeValue);
914                         break;
915
916                 case 0x13:              /* Etag */
917                         ti = proto_tree_add_string (tree, hf_wsp_header_etag,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
918                         break;
919
920                 case 0x14:              /* Expires */
921                         switch (valueLen)
922                         {
923                                 case 1:
924                                 case 2:
925                                         fprintf (stderr, "dissect_wsp: Expires value length %d NYI\n", valueLen);
926                                         break;
927                                 case 3:
928                                         timeValue.tv_sec = tvb_get_ntoh24 (value_buff, 0);
929                                         break;
930                                 case 4:
931                                         timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
932                                         break;
933                         };
934                         ti = proto_tree_add_time (tree, hf_wsp_header_expires, header_buff, offset, headerLen, &timeValue);
935                         break;
936
937                 case 0x17:              /* If-Modified-Since */
938                         if (valueLen == 4)
939                         {
940                                 timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
941                         }
942                         else
943                         {
944                                 timeValue.tv_sec = 0;
945                         }
946                         ti = proto_tree_add_time (tree, hf_wsp_header_if_modified_since, header_buff, offset, headerLen, &timeValue);
947                         break;
948                                 
949                 case 0x1C:              /* Location */
950                         ti = proto_tree_add_string (tree, hf_wsp_header_location,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
951                         break;
952
953                 case 0x1D:              /* Last-Modified */
954                         timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
955                         ti = proto_tree_add_time (tree, hf_wsp_header_last_modified, header_buff, offset, headerLen, &timeValue);
956                         break;
957                                 
958                 case 0x1F:              /* Pragma */
959                         if (peek == 0x80)
960                         {
961                                 proto_tree_add_text (tree, header_buff, 0, headerLen, "Pragma: No-cache");
962                         }
963                         else
964                         {
965                                 proto_tree_add_text (tree, header_buff, 0, headerLen, "Unsupported Header (0x%02X)", (tvb_get_guint8 (header_buff, 0) & 0x7F));
966                         }
967                         break;
968                                 
969                 case 0x26:              /* Server */
970                         ti = proto_tree_add_string (tree, hf_wsp_header_server,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
971                         break;
972
973                 case 0x29:              /* User-Agent */
974                         ti = proto_tree_add_string (tree, hf_wsp_header_user_agent,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
975                         break;
976
977                 default:
978                         ti = proto_tree_add_text (tree, header_buff, 0, headerLen, "Unsupported Header (0x%02X)", (tvb_get_guint8 (header_buff, 0) & 0x7F));
979                         break;
980                 }
981         }
982         else
983         {
984                 /* Special case header X-WAP.TOD that is sometimes followed
985                  * by a 4-byte date value */
986                 if (strncasecmp ("x-wap.tod", tvb_get_ptr (header_buff, 0, headerLen), 9) == 0)
987                 {
988                         if (tvb_reported_length (value_buff) == 4)      /* Probably a date value */
989                         {
990                                 timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
991                                 ti = proto_tree_add_time (tree, hf_wsp_header_x_wap_tod, header_buff, offset, headerLen, &timeValue);
992                         }
993                         else
994                         {
995                                 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));
996                         }
997                 }
998                 else
999                 {
1000                         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));
1001                 }
1002         }
1003
1004 }
1005
1006 guint
1007 get_value_length (tvbuff_t *tvb, guint offset, guint *nextOffset)
1008 {
1009         guint value = 0;
1010         guint count = 0;
1011         guint octet = tvb_get_guint8 (tvb, offset);
1012
1013         if (octet <= 30)        /* Short length */
1014         {
1015                 value = octet;
1016                 *nextOffset = offset+1;
1017         }
1018         else if (octet == 31)
1019         {
1020                 value = tvb_get_guintvar (tvb, offset+1, &count);
1021                 *nextOffset = offset+1+count;
1022         }
1023         else
1024         {
1025                 fprintf (stderr, "dissect_wsp: get_value_length: case NYI\n");
1026         }
1027
1028         return (value);
1029 }
1030
1031 guint
1032 add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset, guint *contentType)
1033 {
1034         proto_tree *contentTypeTree;
1035         guint nextOffset = offset;
1036         guint fieldLength = 0;
1037         guint octet = tvb_get_guint8 (tvb, offset);
1038         guint totalSizeOfField = 0;
1039
1040         if (octet <= 31)
1041         {
1042                 fieldLength = get_value_length (tvb, offset, &nextOffset);
1043                 totalSizeOfField = (nextOffset-offset)+fieldLength;
1044         }
1045         else if (octet & 0x80)
1046         {
1047                 fieldLength = 1;
1048                 totalSizeOfField = 1;
1049         }
1050         else
1051         {
1052                 fprintf (stderr, "dissect-wsp: Content-type is un-supported\n");
1053         }
1054
1055         *contentType = (tvb_get_guint8 (tvb, nextOffset) & 0x7F);
1056         contentTypeTree = proto_tree_add_uint (tree, hf_wsp_content_type, tvb, offset, totalSizeOfField, (tvb_get_guint8(tvb,nextOffset++) & 0x7F));
1057
1058         while (nextOffset < (offset+totalSizeOfField))
1059         {
1060                 /* add_parameter */
1061                 nextOffset = add_parameter (contentTypeTree, tvb, nextOffset);
1062         }
1063
1064         return (offset+totalSizeOfField);
1065 }
1066
1067 guint
1068 add_parameter (proto_tree *tree, tvbuff_t *tvb, guint offset)
1069 {
1070         guint octet = tvb_get_guint8 (tvb, offset);
1071         if (octet & 0x80)       /* Short integer */
1072         {
1073                 offset++;
1074                 octet = octet & 0x7F;
1075                 switch ( octet )
1076                 {
1077                         case 0x01:
1078                                 offset = add_parameter_charset (tree, tvb, offset, offset-1);
1079                                 break;
1080
1081                         default:
1082                                 fprintf (stderr, "dissect-wsp: add_parameter octet=0x%02x\n", octet);
1083                 };
1084         }
1085         else
1086         {
1087                 fprintf (stderr, "dissect-wsp: add_parameter octet=0x%02x\n", octet);
1088         }
1089
1090         return (offset);
1091 }
1092
1093 guint
1094 add_parameter_charset (proto_tree *tree, tvbuff_t *tvb, guint offset, guint startOffset)
1095 {
1096         guint octet = tvb_get_guint8 (tvb, offset);
1097         if (octet < 31)
1098         {
1099                 offset += octet+1;
1100                 proto_tree_add_item (tree, hf_wsp_parameter_well_known_charset, tvb, startOffset+1, octet, bo_big_endian);
1101         }
1102         else if (octet & 0x80)
1103         {
1104                 offset++;
1105                 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset, tvb, startOffset, offset-startOffset, (octet & 0x7F));
1106         }
1107
1108         return offset;
1109 }
1110
1111 void
1112 add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType)
1113 {
1114         guint offset = 0;
1115         guint variableStart = 0;
1116         guint variableEnd = 0;
1117         guint valueStart = 0;
1118         guint valueEnd = 0;
1119         guint8 peek = 0;
1120         proto_item *ti;
1121         
1122         ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,END_OF_FRAME,bo_little_endian);
1123
1124         if (contentType == 0x12)        /* URL Encoded data */
1125         {
1126                 /* Iterate through post data */
1127                 for (offset = 0; offset < tvb_reported_length (tvb); offset++)
1128                 {
1129                         peek = tvb_get_guint8 (tvb, offset);
1130                         if (peek == '=')
1131                         {
1132                                 variableEnd = offset-1;
1133                                 valueStart = offset+1;
1134                         }
1135                         else if (peek == '&')
1136                         {
1137                                 if (variableEnd > 0)
1138                                 {
1139                                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
1140                                 }
1141                                 variableStart = offset+1;
1142                                 variableEnd = 0;
1143                                 valueStart = 0;
1144                                 valueEnd = 0;
1145                         }
1146                 }
1147
1148                 /* See if there's outstanding data */
1149                 if (variableEnd > 0)
1150                 {
1151                         add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
1152                 }
1153         }
1154 }
1155
1156 void
1157 add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
1158 {
1159         int variableLength = variableEnd-variableStart;
1160         int valueLength = 0;
1161         char *variableBuffer;
1162         char *valueBuffer;
1163
1164         variableBuffer = g_malloc (variableLength+1);
1165         strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength+1);
1166         variableBuffer[variableLength+1] = 0;
1167
1168         if (valueEnd == 0)
1169         {
1170                 valueBuffer = g_malloc (1);
1171                 valueBuffer[0] = 0;
1172                 valueEnd = valueStart;
1173         }
1174         else
1175         {
1176                 valueLength = valueEnd-valueStart;
1177                 valueBuffer = g_malloc (valueLength+1);
1178                 strncpy (valueBuffer, tvb_get_ptr (tvb, valueStart, valueLength), valueLength);
1179                 valueBuffer[valueLength] = 0;
1180         }
1181
1182         /* Check for variables with no value */
1183         if (valueStart >= tvb_reported_length (tvb))
1184         {
1185                 valueStart = tvb_reported_length (tvb);
1186                 valueEnd = valueStart;
1187         }
1188         valueLength = valueEnd-valueStart;
1189
1190         proto_tree_add_text (tree, tvb, variableStart, valueEnd-variableStart, "%s: %s", variableBuffer, valueBuffer);
1191
1192         g_free (variableBuffer);
1193         g_free (valueBuffer);
1194 }
1195
1196 /* Register the protocol with Ethereal */
1197 void
1198 proto_register_wsp(void)
1199 {                 
1200
1201 /* Setup list of header fields */
1202         static hf_register_info hf[] = {
1203                 { &hf_wsp_header_tid,
1204                         {       "Transmission ID",           
1205                                 "wsp.TID",
1206                                  FT_UINT8, BASE_HEX, NULL, 0x00,
1207                                 "Transmission ID" 
1208                         }
1209                 },
1210                 { &hf_wsp_header_pdu_type,
1211                         {       "PDU Type",           
1212                                 "wsp.pdu-type",
1213                                  FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
1214                                 "PDU Type" 
1215                         }
1216                 },
1217                 { &hf_wsp_version_major,
1218                         {       "Version (Major)",           
1219                                 "wsp.version.major",
1220                                  FT_UINT8, BASE_DEC, NULL, 0xF0,
1221                                 "Version (Major)" 
1222                         }
1223                 },
1224                 { &hf_wsp_version_minor,
1225                         {       "Version (Minor)",           
1226                                 "wsp.version.minor",
1227                                  FT_UINT8, BASE_DEC, NULL, 0x0F,
1228                                 "Version (Minor)" 
1229                         }
1230                 },
1231                 { &hf_wsp_capability_length,
1232                         {       "Capability Length",           
1233                                 "wsp.capability.length",
1234                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1235                                 "Capability Length" 
1236                         }
1237                 },
1238                 { &hf_wsp_header_length,
1239                         {       "Headers Length",           
1240                                 "wsp.headers-length",
1241                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1242                                 "Headers Length" 
1243                         }
1244                 },
1245                 { &hf_wsp_capabilities_section,
1246                         {       "Capabilities",           
1247                                 "wsp.capabilities",
1248                                  FT_NONE, BASE_DEC, NULL, 0x00,
1249                                 "Capabilities" 
1250                         }
1251                 },
1252                 { &hf_wsp_headers_section,
1253                         {       "Headers",           
1254                                 "wsp.headers",
1255                                  FT_NONE, BASE_DEC, NULL, 0x00,
1256                                 "Headers" 
1257                         }
1258                 },
1259                 { &hf_wsp_header,
1260                         {       "Header",           
1261                                 "wsp.headers.header",
1262                                  FT_NONE, BASE_DEC, NULL, 0x00,
1263                                 "Header" 
1264                         }
1265                 },
1266                 { &hf_wsp_header_uri_len,
1267                         {       "URI Length",           
1268                                 "wsp.uri-length",
1269                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1270                                 "URI Length" 
1271                         }
1272                 },
1273                 { &hf_wsp_header_uri,
1274                         {       "URI",           
1275                                 "wsp.uri",
1276                                  FT_STRING, BASE_NONE, NULL, 0x00,
1277                                 "URI" 
1278                         }
1279                 },
1280                 { &hf_wsp_server_session_id,
1281                         {       "Server Session ID",           
1282                                 "wsp.server.session-id",
1283                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1284                                 "Server Session ID" 
1285                         }
1286                 },
1287                 { &hf_wsp_header_status,
1288                         {       "Status",           
1289                                 "wsp.reply.status",
1290                                  FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
1291                                 "Status" 
1292                         }
1293                 },
1294                 { &hf_wsp_content_type,
1295                         {       "Content Type",           
1296                                 "wsp.content-type.type",
1297                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
1298                                 "Content Type" 
1299                         }
1300                 },
1301                 { &hf_wsp_parameter_well_known_charset,
1302                         {       "Charset",           
1303                                 "wsp.content-type.parameter.charset",
1304                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
1305                                 "Charset" 
1306                         }
1307                 },
1308                 { &hf_wsp_reply_data,
1309                         {       "Data",           
1310                                 "wsp.reply.data",
1311                                  FT_NONE, BASE_NONE, NULL, 0x00,
1312                                 "Data" 
1313                         }
1314                 },
1315                 { &hf_wsp_header_accept,
1316                         {       "Accept",           
1317                                 "wsp.header.accept",
1318                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1319                                  FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
1320                                 "Accept" 
1321                         }
1322                 },
1323                 { &hf_wsp_header_accept_str,
1324                         {       "Accept",           
1325                                 "wsp.header.accept.string",
1326                                  FT_STRING, BASE_NONE, NULL, 0x00,
1327                                 "Accept" 
1328                         }
1329                 },
1330                 { &hf_wsp_header_accept_charset,
1331                         {       "Accept-Charset",           
1332                                 "wsp.header.accept-charset",
1333                                  FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
1334                                 "Accept-Charset" 
1335                         }
1336                 },
1337                 { &hf_wsp_header_accept_language,
1338                         {       "Accept-Language",           
1339                                 "wsp.header.accept-language",
1340                                  FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
1341                                 "Accept-Language" 
1342                         }
1343                 },
1344                 { &hf_wsp_header_accept_ranges,
1345                         {       "Accept-Ranges",           
1346                                 "wsp.header.accept-ranges",
1347                                  FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
1348                                 "Accept-Ranges" 
1349                         }
1350                 },
1351                 { &hf_wsp_header_age,
1352                         {       "Age",           
1353                                 "wsp.header.age",
1354                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1355                                 "Age" 
1356                         }
1357                 },
1358                 { &hf_wsp_header_cache_control,
1359                         {       "Cache-Control",           
1360                                 "wsp.header.cache-control",
1361                                  FT_UINT8, BASE_HEX, VALS ( vals_cache_control ), 0x00,
1362                                 "Cache-Control" 
1363                         }
1364                 },
1365                 { &hf_wsp_header_content_length,
1366                         {       "Content-Length",           
1367                                 "wsp.header.content-length",
1368                                  FT_UINT32, BASE_DEC, NULL, 0x00,
1369                                 "Content-Length" 
1370                         }
1371                 },
1372                 { &hf_wsp_header_date,
1373                         {       "Date",           
1374                                 "wsp.header.date",
1375                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1376                                 "Date" 
1377                         }
1378                 },
1379                 { &hf_wsp_header_etag,
1380                         {       "Etag",           
1381                                 "wsp.header.etag",
1382                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1383                                  FT_STRING, BASE_NONE, NULL, 0x00,
1384                                 "Etag" 
1385                         }
1386                 },
1387                 { &hf_wsp_header_expires,
1388                         {       "Expires",           
1389                                 "wsp.header.expires",
1390                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1391                                 "Expires" 
1392                         }
1393                 },
1394                 { &hf_wsp_header_last_modified,
1395                         {       "Last-Modified",           
1396                                 "wsp.header.last-modified",
1397                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1398                                 "Last-Modified" 
1399                         }
1400                 },
1401                 { &hf_wsp_header_location,
1402                         {       "Location",           
1403                                 "wsp.header.location",
1404                                  FT_STRING, BASE_NONE, NULL, 0x00,
1405                                 "Location" 
1406                         }
1407                 },
1408                 { &hf_wsp_header_if_modified_since,
1409                         {       "If-Modified-Since",           
1410                                 "wsp.header.if-modified-since",
1411                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1412                                 "If-Modified-Since" 
1413                         }
1414                 },
1415                 { &hf_wsp_header_server,
1416                         {       "Server",           
1417                                 "wsp.header.server",
1418                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1419                                  FT_STRING, BASE_NONE, NULL, 0x00,
1420                                 "Server" 
1421                         }
1422                 },
1423                 { &hf_wsp_header_user_agent,
1424                         {       "User-Agent",           
1425                                 "wsp.header.user-agent",
1426                                  /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1427                                  FT_STRING, BASE_NONE, NULL, 0x00,
1428                                 "User-Agent" 
1429                         }
1430                 },
1431                 { &hf_wsp_header_application_header,
1432                         {       "Application Header",           
1433                                 "wsp.header.application-header",
1434                                  FT_STRING, BASE_NONE, NULL, 0x00,
1435                                 "Application Header" 
1436                         }
1437                 },
1438                 { &hf_wsp_header_application_value,
1439                         {       "Application Header Value",           
1440                                 "wsp.header.application-header.value",
1441                                  FT_STRING, BASE_NONE, NULL, 0x00,
1442                                 "Application Header Value" 
1443                         }
1444                 },
1445                 { &hf_wsp_header_x_wap_tod,
1446                         {       "X-WAP.TOD",           
1447                                 "wsp.header.x_wap_tod",
1448                                  FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1449                                 "X-WAP.TOD" 
1450                         }
1451                 },
1452                 { &hf_wsp_post_data,
1453                         {       "Post Data",           
1454                                 "wsp.post.data",
1455                                  FT_NONE, BASE_NONE, NULL, 0x00,
1456                                 "Post Data" 
1457                         }
1458                 },
1459         };
1460         
1461 /* Setup protocol subtree array */
1462         static gint *ett[] = {
1463                 &ett_wsp,
1464                 &ett_header,
1465                 &ett_headers,
1466                 &ett_capabilities,
1467                 &ett_content_type,
1468         };
1469
1470 /* Register the protocol name and description */
1471         proto_wsp = proto_register_protocol(
1472                 "Wireless Session Protocol",    /* protocol name for use by ethereal */ 
1473                 "WSP",                          /* short version of name */
1474                 "wap-wsp"                       /* Abbreviated protocol name, should Match IANA 
1475                                                     < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
1476                                                   */
1477         );
1478
1479 /* Required function calls to register the header fields and subtrees used  */
1480         proto_register_field_array(proto_wsp, hf, array_length(hf));
1481         proto_register_subtree_array(ett, array_length(ett));
1482
1483         register_dissector("wsp", dissect_wsp, proto_wsp);
1484 };
1485
1486 void
1487 proto_reg_handoff_wsp(void)
1488 {
1489         /* Only connection-less WSP has no previous handler */
1490         dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp, proto_wsp);
1491         /* dissector_add("udp.port", UDP_PORT_WTP_WSP, dissect_wsp, proto_wsp); */
1492         /* dissector_add("udp.port", UDP_PORT_WTLS_WSP, dissect_wsp, proto_wsp); */
1493         /* dissector_add("udp.port", UDP_PORT_WTLS_WTP_WSP, dissect_wsp, proto_wsp); */
1494 }