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