aboutsummaryrefslogtreecommitdiffstats
path: root/packet-wsp.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2000-11-04 03:30:41 +0000
committerGuy Harris <guy@alum.mit.edu>2000-11-04 03:30:41 +0000
commit8c6db228bf7235014a0e2f925db4efb2c30f57ce (patch)
tree732d415025dd7c1affc1e22c54c4cc81d589ae27 /packet-wsp.c
parent50da6b7562bb01fb493df4d253501cf9f6ce86aa (diff)
WAP support, from Neil Hunter.
svn path=/trunk/; revision=2558
Diffstat (limited to 'packet-wsp.c')
-rw-r--r--packet-wsp.c1492
1 files changed, 1492 insertions, 0 deletions
diff --git a/packet-wsp.c b/packet-wsp.c
new file mode 100644
index 0000000000..98fbd649a2
--- /dev/null
+++ b/packet-wsp.c
@@ -0,0 +1,1492 @@
+/* packet-wsp.c (c) 2000 Neil Hunter
+ * Based on original work by Ben Fowler
+ *
+ * Routines to dissect WSP component of WAP traffic.
+ *
+ * $Id: packet-wsp.c,v 1.1 2000/11/04 03:30:40 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.org>
+ * Copyright 1998 Didier Jorand
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef NEED_SNPRINTF_H
+# ifdef HAVE_STDARG_H
+# include <stdarg.h>
+# else
+# include <varargs.h>
+# endif
+# include "snprintf.h"
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include "packet.h"
+#include "packet-wap.h"
+#include "packet-wsp.h"
+
+/* File scoped variables for the protocol and registered fields */
+static int proto_wsp = HF_EMPTY;
+
+/* These fields used by fixed part of header */
+static int hf_wsp_header_tid = HF_EMPTY;
+static int hf_wsp_header_pdu_type = HF_EMPTY;
+static int hf_wsp_version_major = HF_EMPTY;
+static int hf_wsp_version_minor = HF_EMPTY;
+static int hf_wsp_capability_length = HF_EMPTY;
+static int hf_wsp_capabilities_section = HF_EMPTY;
+static int hf_wsp_header_uri_len = HF_EMPTY;
+static int hf_wsp_header_uri = HF_EMPTY;
+static int hf_wsp_server_session_id = HF_EMPTY;
+static int hf_wsp_header_status = HF_EMPTY;
+static int hf_wsp_header_length = HF_EMPTY;
+static int hf_wsp_headers_section = HF_EMPTY;
+static int hf_wsp_header = HF_EMPTY;
+static int hf_wsp_content_type = HF_EMPTY;
+static int hf_wsp_parameter_well_known_charset = HF_EMPTY;
+static int hf_wsp_reply_data = HF_EMPTY;
+static int hf_wsp_post_data = HF_EMPTY;
+
+static int hf_wsp_header_accept = HF_EMPTY;
+static int hf_wsp_header_accept_str = HF_EMPTY;
+static int hf_wsp_header_accept_charset = HF_EMPTY;
+static int hf_wsp_header_accept_language = HF_EMPTY;
+static int hf_wsp_header_accept_ranges = HF_EMPTY;
+static int hf_wsp_header_cache_control = HF_EMPTY;
+static int hf_wsp_header_content_length = HF_EMPTY;
+static int hf_wsp_header_age = HF_EMPTY;
+static int hf_wsp_header_date = HF_EMPTY;
+static int hf_wsp_header_etag = HF_EMPTY;
+static int hf_wsp_header_expires = HF_EMPTY;
+static int hf_wsp_header_last_modified = HF_EMPTY;
+static int hf_wsp_header_location = HF_EMPTY;
+static int hf_wsp_header_if_modified_since = HF_EMPTY;
+static int hf_wsp_header_server = HF_EMPTY;
+static int hf_wsp_header_user_agent = HF_EMPTY;
+static int hf_wsp_header_application_header = HF_EMPTY;
+static int hf_wsp_header_application_value = HF_EMPTY;
+static int hf_wsp_header_x_wap_tod = HF_EMPTY;
+
+/* Initialize the subtree pointers */
+static gint ett_wsp = ETT_EMPTY;
+static gint ett_header = ETT_EMPTY;
+static gint ett_headers = ETT_EMPTY;
+static gint ett_capabilities = ETT_EMPTY;
+static gint ett_content_type = ETT_EMPTY;
+
+static const value_string vals_pdu_type[] = {
+ { 0x00, "Reserved" },
+ { 0x01, "Connect" },
+ { 0x02, "ConnectReply" },
+ { 0x03, "Redirect" },
+ { 0x04, "Reply" },
+ { 0x05, "Disconnect" },
+ { 0x06, "Push" },
+ { 0x07, "ConfirmedPush" },
+ { 0x08, "Suspend" },
+ { 0x09, "Resume" },
+
+ /* 0x10 - 0x3F Unassigned */
+
+ { 0x40, "Get" },
+ { 0x41, "Options" },
+ { 0x42, "Head" },
+ { 0x43, "Delete" },
+ { 0x44, "Trace" },
+
+ /* 0x45 - 0x4F Unassigned (Get PDU) */
+ /* 0x50 - 0x5F Extended method (Get PDU) */
+
+ { 0x60, "Post" },
+ { 0x61, "Put" },
+
+ /* 0x62 - 0x6F Unassigned (Post PDU) */
+ /* 0x70 - 0x7F Extended method (Post PDU) */
+ /* 0x80 - 0xFF Reserved */
+
+};
+
+static const value_string vals_status[] = {
+ /* 0x00 - 0x0F Reserved */
+
+ { 0x10, "Continue" },
+ { 0x11, "Switching Protocols" },
+
+ { 0x20, "OK" },
+ { 0x21, "Created" },
+ { 0x22, "Accepted" },
+ { 0x23, "Non-Authoritative Information" },
+ { 0x24, "No Content" },
+ { 0x25, "Reset Content" },
+ { 0x26, "Partial Content" },
+
+ { 0x30, "Multiple Choices" },
+ { 0x31, "Moved Permanently" },
+ { 0x32, "Moved Temporarily" },
+ { 0x33, "See Other" },
+ { 0x34, "Not Modified" },
+ { 0x35, "Use Proxy" },
+
+ { 0x40, "Bad Request" },
+ { 0x41, "Unauthorised" },
+ { 0x42, "Payment Required" },
+ { 0x43, "Forbidden" },
+ { 0x44, "Not Found" },
+ { 0x45, "Method Not Allowed" },
+ { 0x46, "Not Acceptable" },
+ { 0x47, "Proxy Authentication Required" },
+ { 0x48, "Request Timeout" },
+ { 0x49, "Conflict" },
+ { 0x4A, "Gone" },
+ { 0x4B, "Length Required" },
+ { 0x4C, "Precondition Failed" },
+ { 0x4D, "Request Entity Too Large" },
+ { 0x4E, "Request-URI Too Large" },
+ { 0x4F, "Unsupported Media Type" },
+
+ { 0x60, "Internal Server Error" },
+ { 0x61, "Not Implemented" },
+ { 0x62, "Bad Gateway" },
+ { 0x63, "Service Unavailable" },
+ { 0x64, "Gateway Timeout" },
+ { 0x65, "HTTP Version Not Supported" },
+};
+
+static const value_string vals_content_types[] = {
+ { 0x00, "*/*" },
+ { 0x01, "text/*" },
+ { 0x02, "text/html" },
+ { 0x03, "text/plain" },
+ { 0x04, "text/x-hdml" },
+ { 0x05, "text/x-ttml" },
+ { 0x06, "text/x-vCalendar" },
+ { 0x07, "text/x-vCard" },
+ { 0x08, "text/vnd.wap.wml" },
+ { 0x09, "text/vnd.wap.wmlscript" },
+ { 0x0A, "text/vnd.wap.channel" },
+ { 0x0B, "Multipart/*" },
+ { 0x0C, "Multipart/mixed" },
+ { 0x0D, "Multipart/form-data" },
+ { 0x0E, "Multipart/byteranges" },
+ { 0x0F, "Multipart/alternative" },
+ { 0x10, "application/*" },
+ { 0x11, "application/java-vm" },
+ { 0x12, "application/x-www-form-urlencoded" },
+ { 0x13, "application/x-hdmlc" },
+ { 0x14, "application/vnd.wap.wmlc" },
+ { 0x15, "application/vnd.wap.wmlscriptc" },
+ { 0x16, "application/vnd.wap.channelc" },
+ { 0x17, "application/vnd.wap.uaprof" },
+ { 0x18, "application/vnd.wap.wtls-ca-certificate" },
+ { 0x19, "application/vnd.wap.wtls-user-certificate" },
+ { 0x1A, "application/x-x509-ca-cert" },
+ { 0x1B, "application/x-x509-user-cert" },
+ { 0x1C, "image/*" },
+ { 0x1D, "image/gif" },
+ { 0x1E, "image/jpeg" },
+ { 0x1F, "image/tiff" },
+ { 0x20, "image/png" },
+ { 0x21, "image/vnd.wap.wbmp" },
+ { 0x22, "application/vnd.wap.multipart.*" },
+ { 0x23, "application/vnd.wap.multipart.mixed" },
+ { 0x24, "application/vnd.wap.multipart.form-data" },
+ { 0x25, "application/vnd.wap.multipart.byteranges" },
+ { 0x26, "application/vnd.wap.multipart.alternative" },
+ { 0x27, "application/xml" },
+ { 0x28, "text/xml" },
+ { 0x29, "application/vnd.wap.wbxml" },
+ { 0x2A, "application/x-x968-cross-cert" },
+ { 0x2B, "application/x-x968-ca-cert" },
+ { 0x2C, "application/x-x968-user-cert" },
+ { 0x2D, "text/vnd.wap.si" },
+ { 0x2E, "application/vnd.wap.sic" },
+ { 0x2F, "text/vnd.wap.sl" },
+ { 0x30, "application/vnd.wap.slc" },
+ { 0x31, "text/vnd.wap.co" },
+ { 0x32, "application/vnd.wap.coc" },
+ { 0x33, "application/vnd.wap.multipart.related" },
+ { 0x34, "application/vnd.wap.sia" },
+};
+
+static const value_string vals_character_sets[] = {
+ { 0x0003, "us-ascii" },
+ { 0x0004, "iso-8859-1" },
+ { 0x0005, "iso-8859-2" },
+ { 0x0006, "iso-8859-3" },
+ { 0x0007, "iso-8859-4" },
+ { 0x0008, "iso-8859-5" },
+ { 0x0009, "iso-8859-6" },
+ { 0x000A, "iso-8859-7" },
+ { 0x000B, "iso-8859-8" },
+ { 0x000C, "iso-8859-9" },
+ { 0x0011, "shift_JIS" },
+ { 0x006A, "utf-8" },
+ { 0x03E8, "iso-10646-ucs-2" },
+ { 0x07EA, "big5" },
+};
+
+static const value_string vals_languages[] = {
+ { 0x19, "English (en)" },
+};
+
+static const value_string vals_accept_ranges[] = {
+ { 0x80, "None" },
+ { 0x81, "Bytes" },
+};
+
+static const value_string vals_cache_control[] = {
+ { 0x80, "No-cache" },
+ { 0x81, "No-store" },
+ { 0x82, "Max-age" },
+ { 0x83, "Max-stale" },
+ { 0x84, "Min-fresh" },
+ { 0x85, "Only-if-cached" },
+ { 0x86, "Public" },
+ { 0x87, "Private" },
+ { 0x88, "No-transform" },
+ { 0x89, "Must-revalidate" },
+ { 0x8A, "Proxy-revalidate" },
+};
+
+enum {
+ RESERVED = 0x00,
+ CONNECT = 0x01,
+ CONNECTREPLY = 0x02,
+ REDIRECT = 0x03, /* No sample data */
+ REPLY = 0x04,
+ DISCONNECT = 0x05,
+ PUSH = 0x06, /* No sample data */
+ CONFIRMEDPUSH = 0x07, /* No sample data */
+ SUSPEND = 0x08, /* No sample data */
+ RESUME = 0x09, /* No sample data */
+
+ GET = 0x40,
+ OPTIONS = 0x41, /* No sample data */
+ HEAD = 0x42, /* No sample data */
+ DELETE = 0x43, /* No sample data */
+ TRACE = 0x44, /* No sample data */
+
+ POST = 0x60,
+ PUT = 0x61, /* No sample data */
+};
+
+void add_uri (proto_tree *, tvbuff_t *, guint, guint);
+void add_headers (proto_tree *, tvbuff_t *);
+void add_header (proto_tree *, tvbuff_t *, tvbuff_t *);
+guint get_value_length (tvbuff_t *, guint, guint *);
+guint add_content_type (proto_tree *, tvbuff_t *, guint, guint *);
+guint add_parameter (proto_tree *, tvbuff_t *, guint);
+guint add_parameter_charset (proto_tree *, tvbuff_t *, guint, guint);
+void add_post_data (proto_tree *, tvbuff_t *, guint);
+void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
+
+/*
+ * Accessor to retrieve variable length int as used in WAP protocol.
+ * The value is encoded in the lower 7 bits. If the top bit is set, then the
+ * value continues into the next byte.
+ * The octetCount parameter holds the number of bytes read in order to return
+ * the final value. Can be pre-initialised to start at offset+count.
+*/
+guint
+tvb_get_guintvar (tvbuff_t *tvb, guint offset, guint *octetCount)
+{
+ guint value = 0;
+ guint octet;
+ guint counter = 0;
+ char cont = 1;
+
+ if (octetCount != NULL)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Starting tvb_get_guintvar at offset %d, count=NULL\n", offset);
+#endif
+ }
+ else
+ {
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Starting tvb_get_guintvar at offset %d, count=%d\n", offset, *octetCount);
+#endif
+ counter = *octetCount;
+ }
+
+ while (cont != 0)
+ {
+ value<<=7; /* Value only exists in 7 of the 8 bits */
+ octet = tvb_get_guint8 (tvb, offset+counter);
+ counter++;
+ value += (octet & 0x7F);
+ cont = (octet & 0x80);
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: octet is %d (0x%02x), count=%d, value=%d, cont=%d\n", octet, octet, counter, value, cont);
+#endif
+ }
+
+ if (octetCount != NULL)
+ {
+ *octetCount = counter;
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Leaving tvb_get_guintvar count=%d\n", *octetCount);
+#endif
+ }
+
+ return (value);
+}
+
+void
+dissect_wsp_no_tvbuff(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+{
+ packet_info *pinfo = &pi;
+ tvbuff_t *tvb = tvb_create_from_top(offset);
+ dissect_wsp (tvb, pinfo, tree);
+}
+
+/* Code to actually dissect the packets */
+void
+dissect_wsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ frame_data *fdata = pinfo->fd;
+ int offset = 0;
+
+ char szInfo[ 50 ];
+ int cchInfo;
+ char pdut;
+ guint count = 0;
+ guint value = 0;
+ guint uriLength = 0;
+ guint uriStart = 0;
+ guint capabilityLength = 0;
+ guint capabilityStart = 0;
+ guint headersLength = 0;
+ guint headerLength = 0;
+ guint headerStart = 0;
+ guint nextOffset = 0;
+ guint contentTypeStart = 0;
+ guint contentType = 0;
+ tvbuff_t *tmp_tvb;
+
+/* Set up structures we will need to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_tree *wsp_tree;
+/* proto_tree *wsp_header_fixed; */
+ proto_tree *wsp_capabilities;
+
+/* This field shows up as the "Info" column in the display; you should make
+ it, if possible, summarize what's in the packet, so that a user looking
+ at the list of packets can tell what type of packet it is.
+ "col_add_fstr()" can be used instead of "col_add_str()"; it takes
+ "printf()"-like arguments. */
+
+ /* Display protocol type depending on the port */
+ if (check_col(fdata, COL_PROTOCOL))
+ {
+ switch ( pinfo->match_port )
+ {
+ case UDP_PORT_WSP:
+ col_add_fstr(fdata, COL_PROTOCOL, "WSP" );
+ break;
+ case UDP_PORT_WTLS_WSP:
+ col_add_fstr(fdata, COL_PROTOCOL, "WTLS+WSP" );
+ break;
+ }
+ }
+
+ /* Connection-less mode has a TID first */
+ if ((pinfo->match_port == UDP_PORT_WSP) || (pinfo->match_port == UDP_PORT_WTLS_WSP))
+ {
+ offset++;
+ };
+
+ /* Find the PDU type */
+ pdut = tvb_get_guint8 (tvb, offset);
+
+ /* Develop the string to put in the Info column */
+ cchInfo = snprintf( szInfo, sizeof( szInfo ), "WSP %s",
+ match_strval (( int )pdut, vals_pdu_type));
+ if (check_col(fdata, COL_INFO)) {
+ col_add_str(fdata, COL_INFO, szInfo );
+ };
+
+/* In the interest of speed, if "tree" is NULL, don't do any work not
+ necessary to generate protocol tree items. */
+ if (tree) {
+/* NOTE: The offset and length values in the previous call to
+ "proto_tree_add_item()" define what data bytes to highlight in the hex
+ display window when the line in the protocol tree display
+ corresponding to that item is selected.
+
+ END_OF_FRAME is a handy way to highlight all data from the offset to
+ the end of the packet. */
+/* ti = proto_tree_add_item(tree, proto_wsp, NullTVB, offset, END_OF_FRAME, NULL); */
+/*
+ ti = proto_tree_add_item(tree, proto_wsp, tvb, offset, END_OF_FRAME, NULL);
+ wsp_tree = proto_item_add_subtree(ti, ett_wsp);
+*/
+
+ ti = proto_tree_add_item(tree, proto_wsp, tvb, 0, END_OF_FRAME, bo_little_endian);
+ wsp_tree = proto_item_add_subtree(ti, ett_wsp);
+
+/* Code to process the packet goes here */
+/*
+ wsp_header_fixed = proto_item_add_subtree(
+ ti,
+ ett_header
+ );
+*/
+
+ /* Add common items: only TID and PDU Type */
+
+ /* TID Field is always first (if it exists) */
+ if ((pinfo->match_port == UDP_PORT_WSP) || (pinfo->match_port == UDP_PORT_WTLS_WSP))
+ {
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_header_tid,tvb,0,1,bo_little_endian);
+ }
+
+ ti = proto_tree_add_item(
+ wsp_tree, /* tree */
+ hf_wsp_header_pdu_type, /* id */
+ tvb,
+ offset++, /* start of high light */
+ 1, /* length of high light */
+ bo_little_endian /* value */
+ );
+
+ switch (pdut)
+ {
+ case CONNECT:
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
+ offset++;
+ capabilityStart = offset;
+ capabilityLength = tvb_get_guintvar (tvb, offset, &count);
+ offset += count;
+ ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
+
+ headerStart = offset;
+ headerLength = tvb_get_guintvar (tvb, offset, &count);
+ offset += count;
+ ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
+ if (capabilityLength > 0)
+ {
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_capabilities_section,tvb,offset,capabilityLength,bo_little_endian);
+ wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
+ offset += capabilityLength;
+ }
+
+ if (headerLength > 0)
+ {
+ tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
+ add_headers (wsp_tree, tmp_tvb);
+ }
+
+ break;
+
+ case CONNECTREPLY:
+ value = tvb_get_guintvar (tvb, offset, &count);
+ ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
+ offset += count;
+
+ capabilityStart = offset;
+ capabilityLength = tvb_get_guintvar (tvb, offset, &count);
+ offset += count;
+ ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
+
+ headerStart = offset;
+ headerLength = tvb_get_guintvar (tvb, offset, &count);
+ offset += count;
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,bo_little_endian);
+ if (capabilityLength > 0)
+ {
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_capabilities_section,tvb,offset,capabilityLength,bo_little_endian);
+ wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
+ offset += capabilityLength;
+ }
+
+ if (headerLength > 0)
+ {
+
+ /*
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_headers_section,tvb,offset,headerLength,bo_little_endian);
+ wsp_headers = proto_item_add_subtree( ti, ett_headers );
+ */
+ tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
+ add_headers (wsp_tree, tmp_tvb);
+ }
+
+ break;
+
+ case DISCONNECT:
+ value = tvb_get_guintvar (tvb, offset, &count);
+ ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
+ break;
+
+ case GET:
+ /* Length of URI and size of URILen field */
+ value = tvb_get_guintvar (tvb, offset, &count);
+ nextOffset = offset + count;
+ add_uri (wsp_tree, tvb, offset, nextOffset);
+ offset += (value+1);
+ tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
+ add_headers (wsp_tree, tmp_tvb);
+ break;
+
+ case POST:
+ uriStart = offset;
+ uriLength = tvb_get_guintvar (tvb, offset, &count);
+ headerStart = uriStart+count;
+ headersLength = tvb_get_guintvar (tvb, headerStart, &count);
+ offset = headerStart + count;
+
+ add_uri (wsp_tree, tvb, uriStart, offset);
+ offset += uriLength;
+
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,bo_little_endian);
+
+ contentTypeStart = offset;
+ nextOffset = add_content_type (wsp_tree, tvb, offset, &contentType);
+
+ /* Add headers subtree that will hold the headers fields */
+ /* Runs from nextOffset for value-(length of content-type field)*/
+ headerLength = headersLength-(nextOffset-contentTypeStart);
+ tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
+ add_headers (wsp_tree, tmp_tvb);
+
+ /* TODO: Post DATA */
+ /* Runs from start of headers+headerLength to END_OF_FRAME */
+ offset = nextOffset+headerLength;
+ tmp_tvb = tvb_new_subset (tvb, offset, tvb_reported_length (tvb)-offset, tvb_reported_length (tvb)-offset);
+ add_post_data (wsp_tree, tmp_tvb, contentType);
+ break;
+
+ case REPLY:
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
+ value = tvb_get_guintvar (tvb, offset+1, &count);
+ nextOffset = offset + 1 + count;
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,bo_little_endian);
+
+ contentTypeStart = nextOffset;
+ nextOffset = add_content_type (wsp_tree, tvb, nextOffset, &contentType);
+
+ /* Add headers subtree that will hold the headers fields */
+ /* Runs from nextOffset for value-(length of content-type field)*/
+ headerLength = value-(nextOffset-contentTypeStart);
+ tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
+ add_headers (wsp_tree, tmp_tvb);
+ offset += count+value+1;
+
+ /* TODO: Data - decode WMLC */
+ /* Runs from offset+1+count+value+1 to END_OF_FRAME */
+ if (offset < tvb_reported_length (tvb))
+ {
+ ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,END_OF_FRAME,bo_little_endian);
+ }
+ break;
+ }
+ }
+}
+
+void
+add_uri (proto_tree *tree, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
+{
+ proto_item *ti;
+ guint8 terminator = 0;
+ char *newBuffer;
+
+ guint count = 0;
+ guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
+
+ ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
+
+ /* If string doesn't end with a 0x00, we need to add one to be on the safe side */
+ terminator = tvb_get_guint8 (tvb, URIOffset+uriLen-1);
+ if (terminator != 0)
+ {
+ newBuffer = g_malloc (uriLen+1);
+ strncpy (newBuffer, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
+ newBuffer[uriLen] = 0;
+ ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer);
+ g_free (newBuffer);
+ }
+ else
+ {
+ ti = proto_tree_add_item (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,bo_little_endian);
+ }
+}
+
+void
+add_headers (proto_tree *tree, tvbuff_t *tvb)
+{
+ proto_item *ti;
+ proto_tree *wsp_headers;
+ guint offset = 0;
+ guint headersLen = tvb_reported_length (tvb);
+ guint8 headerStart = 0;
+ guint peek = 0;
+ tvbuff_t *header_buff;
+ tvbuff_t *value_buff;
+ guint count = 0;
+ guint valueStart = 0;
+ guint valueEnd = 0;
+
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, headersLen);
+#endif
+
+ /* End of buffer */
+ if (headersLen <= 0)
+ {
+ return;
+ }
+
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Headers to process\n");
+#endif
+
+ ti = proto_tree_add_item (tree, hf_wsp_headers_section,tvb,offset,headersLen,bo_little_endian);
+ wsp_headers = proto_item_add_subtree( ti, ett_headers );
+
+ /* Parse Headers */
+
+ while (offset < headersLen)
+ {
+ /* Loop round each header */
+ headerStart = offset;
+ peek = tvb_get_guint8 (tvb, headerStart);
+
+ if (peek < 32) /* Short-cut shift delimeter */
+ {
+ fprintf (stderr, "dissect_wsp: header: short-cut shift %d (0x%02X)\n", peek, peek);
+ offset++;
+ }
+ else if (peek == 0x7F) /* Shift delimeter */
+ {
+ fprintf (stderr, "dissect_wsp: header: shift delimeter %d (0x%02X)\n", peek, peek);
+ offset++;
+ }
+ else if (peek < 127)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: header: application-header start %d (0x%02X)\n", peek, peek);
+#endif
+ while (tvb_get_guint8 (tvb, offset++)) { /* Do nothing, just look for NULL */ }
+ }
+ else if (peek & 0x80) /* Well-known header */
+ {
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: header: well-known %d (0x%02X)\n", peek, peek);
+#endif
+ offset++;
+ }
+
+ /* Get value part of header */
+ valueStart = offset;
+ peek = tvb_get_guint8 (tvb, valueStart);
+ if (peek <= 30)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Looking for %d octets\n", peek);
+#endif
+ valueStart++;
+ valueEnd = offset+1+peek;
+ offset += (peek+1);
+ }
+ else if (peek == 31)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Looking for uintvar octets\n");
+#endif
+ tvb_get_guintvar (tvb, valueStart, &count);
+ valueEnd = offset+1+count;
+ offset += (count+1);
+ }
+ else if (peek <= 127)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Looking for NULL-terminated string\n");
+#endif
+ valueEnd = valueStart+1;
+ while (tvb_get_guint8 (tvb, valueEnd++)) { /* Do nothing, just look for NULL */ }
+ offset = valueEnd;
+ }
+ else
+ {
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Value is %d\n", (peek & 0x7F));
+#endif
+ valueEnd = offset+1;
+ offset++;
+ }
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Creating value buffer from offset %d, size=%d\n", headerStart, (offset-headerStart));
+#endif
+
+ header_buff = tvb_new_subset (tvb, headerStart, (offset-headerStart), (offset-headerStart));
+ value_buff = tvb_new_subset (tvb, valueStart, (valueEnd-valueStart), (valueEnd-valueStart));
+
+ add_header (wsp_headers, header_buff, value_buff);
+ }
+}
+
+void
+add_header (proto_tree *tree, tvbuff_t *header_buff, tvbuff_t *value_buff)
+{
+ guint offset = 0;
+ guint8 headerType = 0;
+ proto_item *ti;
+ guint headerLen = tvb_reported_length (header_buff);
+ guint valueLen = tvb_reported_length (value_buff);
+ guint peek = 0;
+ struct timeval timeValue;
+ guint value = 0;
+
+ headerType = tvb_get_guint8 (header_buff, 0);
+ peek = tvb_get_guint8 (value_buff, 0);
+#ifdef DEBUG
+ fprintf (stderr, "dissect_wsp: Got header 0x%02x\n", headerType);
+ fprintf (stderr, "dissect_wsp: First value octet is 0x%02x\n", peek);
+#endif
+
+ if (headerType == 0x7F)
+ {
+ }
+ else if (headerType < 0x1F)
+ {
+ }
+ else if (headerType & 0x80)
+ {
+ headerType = headerType & 0x7F;
+ switch (headerType)
+ {
+ case 0x00: /* Accept */
+ if (peek & 0x80)
+ {
+ proto_tree_add_uint (tree, hf_wsp_header_accept, header_buff, offset, headerLen, (peek & 0x7F));
+ }
+ else
+ {
+ proto_tree_add_string (tree, hf_wsp_header_accept_str,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
+ }
+ break;
+
+ case 0x01: /* Accept-Charset */
+ if (peek < 31)
+ {
+ /* Peek contains the number of octets to follow */
+ switch (peek)
+ {
+ case 1:
+ proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_guint8 (value_buff, 1) );
+ break;
+ case 2:
+ proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_ntohs (value_buff, 1) );
+ break;
+ case 4:
+ proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_ntohl (value_buff, 1) );
+ break;
+ default:
+ fprintf (stderr, "dissect_wsp: accept-charset size %d NYI\n", peek);
+ }
+ }
+ else if (peek & 0x80)
+ {
+ proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, (peek & 0x7F) );
+ }
+ else
+ {
+ fprintf (stderr, "dissect_wsp: Accept-Charset value %d (0x%02X) NYI\n", peek, peek);
+ }
+ break;
+
+ case 0x03: /* Accept-Language */
+ proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, headerLen, (peek & 0x7F));
+ break;
+
+ case 0x04: /* Accept-Ranges */
+ if ((peek == 128) || (peek == 129))
+ {
+ proto_tree_add_uint (tree, hf_wsp_header_accept_ranges, header_buff, offset, headerLen, peek);
+ }
+ else
+ {
+ fprintf (stderr, "dissect_wsp: accept-ranges NYI\n");
+ }
+
+ break;
+
+ case 0x05: /* Age */
+ switch (valueLen)
+ {
+ case 1:
+ proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_guint8 (value_buff, 0));
+ break;
+ case 2:
+ proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntohs (value_buff, 0));
+ break;
+ case 3:
+ proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntoh24 (value_buff, 0));
+ break;
+ case 4:
+ proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntohl (value_buff, 0));
+ break;
+ };
+ break;
+
+ case 0x08: /* Cache-Control */
+ if (peek & 0x80)
+ {
+ if (valueLen == 1) /* Well-known value */
+ {
+ proto_tree_add_uint (tree, hf_wsp_header_cache_control, header_buff, offset, headerLen, peek);
+ }
+ else
+ {
+ if ((peek == 0x82) || (peek == 0x83) || (peek == 0x84)) /* Delta seconds value to follow */
+ {
+ value = tvb_get_guint8 (value_buff, 1);
+ if (value & 0x80)
+ {
+ proto_tree_add_text (tree, header_buff, 0, headerLen, "Cache-Control: %s %d (0x%02X)",
+ match_strval ((int) peek, vals_cache_control), (value & 0x7F), peek);
+ }
+ else
+ {
+ fprintf (stderr, "dissect_wsp: Cache-Control integer value Delta seconds NYI\n");
+ }
+ }
+ else if ((peek == 0x80) || (peek == 0x87)) /* Fields to follow */
+ {
+ fprintf (stderr, "dissect_wsp: Cache-Control field values NYI\n");
+ }
+ else
+ {
+ fprintf (stderr, "dissect_wsp: Cache-Control cache extension NYI\n");
+ }
+ }
+ }
+ else
+ {
+ fprintf (stderr, "dissect_wsp: Cache-Control cache extension NYI\n");
+ }
+ break;
+
+ case 0x0D: /* Content-Length */
+ if (peek & 0x80)
+ {
+ proto_tree_add_uint (tree, hf_wsp_header_content_length, header_buff, offset, headerLen, (peek & 0x7F));
+ }
+ else
+ {
+ fprintf (stderr, "dissect_wsp: Content-Length long-integer size NYI\n");
+ }
+ break;
+
+ case 0x12: /* Date */
+ timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
+ ti = proto_tree_add_time (tree, hf_wsp_header_date, header_buff, offset, headerLen, &timeValue);
+ break;
+
+ case 0x13: /* Etag */
+ ti = proto_tree_add_string (tree, hf_wsp_header_etag,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
+ break;
+
+ case 0x14: /* Expires */
+ switch (valueLen)
+ {
+ case 1:
+ case 2:
+ fprintf (stderr, "dissect_wsp: Expires value length %d NYI\n", valueLen);
+ break;
+ case 3:
+ timeValue.tv_sec = tvb_get_ntoh24 (value_buff, 0);
+ break;
+ case 4:
+ timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
+ break;
+ };
+ ti = proto_tree_add_time (tree, hf_wsp_header_expires, header_buff, offset, headerLen, &timeValue);
+ break;
+
+ case 0x17: /* If-Modified-Since */
+ if (valueLen == 4)
+ {
+ timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
+ }
+ else
+ {
+ timeValue.tv_sec = 0;
+ }
+ ti = proto_tree_add_time (tree, hf_wsp_header_if_modified_since, header_buff, offset, headerLen, &timeValue);
+ break;
+
+ case 0x1C: /* Location */
+ ti = proto_tree_add_string (tree, hf_wsp_header_location,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
+ break;
+
+ case 0x1D: /* Last-Modified */
+ timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
+ ti = proto_tree_add_time (tree, hf_wsp_header_last_modified, header_buff, offset, headerLen, &timeValue);
+ break;
+
+ case 0x1F: /* Pragma */
+ if (peek == 0x80)
+ {
+ proto_tree_add_text (tree, header_buff, 0, headerLen, "Pragma: No-cache");
+ }
+ else
+ {
+ proto_tree_add_text (tree, header_buff, 0, headerLen, "Unsupported Header (0x%02X)", (tvb_get_guint8 (header_buff, 0) & 0x7F));
+ }
+ break;
+
+ case 0x26: /* Server */
+ ti = proto_tree_add_string (tree, hf_wsp_header_server,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
+ break;
+
+ case 0x29: /* User-Agent */
+ ti = proto_tree_add_string (tree, hf_wsp_header_user_agent,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
+ break;
+
+ default:
+ ti = proto_tree_add_text (tree, header_buff, 0, headerLen, "Unsupported Header (0x%02X)", (tvb_get_guint8 (header_buff, 0) & 0x7F));
+ break;
+ }
+ }
+ else
+ {
+ /* Special case header X-WAP.TOD that is sometimes followed
+ * by a 4-byte date value */
+ if (strncasecmp ("x-wap.tod", tvb_get_ptr (header_buff, 0, headerLen), 9) == 0)
+ {
+ if (tvb_reported_length (value_buff) == 4) /* Probably a date value */
+ {
+ timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
+ ti = proto_tree_add_time (tree, hf_wsp_header_x_wap_tod, header_buff, offset, headerLen, &timeValue);
+ }
+ else
+ {
+ 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));
+ }
+ }
+ else
+ {
+ 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));
+ }
+ }
+
+}
+
+guint
+get_value_length (tvbuff_t *tvb, guint offset, guint *nextOffset)
+{
+ guint value = 0;
+ guint count = 0;
+ guint octet = tvb_get_guint8 (tvb, offset);
+
+ if (octet <= 30) /* Short length */
+ {
+ value = octet;
+ *nextOffset = offset+1;
+ }
+ else if (octet == 31)
+ {
+ value = tvb_get_guintvar (tvb, offset+1, &count);
+ *nextOffset = offset+1+count;
+ }
+ else
+ {
+ fprintf (stderr, "dissect_wsp: get_value_length: case NYI\n");
+ }
+
+ return (value);
+}
+
+guint
+add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset, guint *contentType)
+{
+ proto_tree *contentTypeTree;
+ guint nextOffset = offset;
+ guint fieldLength = 0;
+ guint octet = tvb_get_guint8 (tvb, offset);
+ guint totalSizeOfField = 0;
+
+ if (octet <= 31)
+ {
+ fieldLength = get_value_length (tvb, offset, &nextOffset);
+ totalSizeOfField = (nextOffset-offset)+fieldLength;
+ }
+ else if (octet & 0x80)
+ {
+ fieldLength = 1;
+ totalSizeOfField = 1;
+ }
+ else
+ {
+ fprintf (stderr, "dissect-wsp: Content-type is un-supported\n");
+ }
+
+ *contentType = (tvb_get_guint8 (tvb, nextOffset) & 0x7F);
+ contentTypeTree = proto_tree_add_uint (tree, hf_wsp_content_type, tvb, offset, totalSizeOfField, (tvb_get_guint8(tvb,nextOffset++) & 0x7F));
+
+ while (nextOffset < (offset+totalSizeOfField))
+ {
+ /* add_parameter */
+ nextOffset = add_parameter (contentTypeTree, tvb, nextOffset);
+ }
+
+ return (offset+totalSizeOfField);
+}
+
+guint
+add_parameter (proto_tree *tree, tvbuff_t *tvb, guint offset)
+{
+ guint octet = tvb_get_guint8 (tvb, offset);
+ if (octet & 0x80) /* Short integer */
+ {
+ offset++;
+ octet = octet & 0x7F;
+ switch ( octet )
+ {
+ case 0x01:
+ offset = add_parameter_charset (tree, tvb, offset, offset-1);
+ break;
+
+ default:
+ fprintf (stderr, "dissect-wsp: add_parameter octet=0x%02x\n", octet);
+ };
+ }
+ else
+ {
+ fprintf (stderr, "dissect-wsp: add_parameter octet=0x%02x\n", octet);
+ }
+
+ return (offset);
+}
+
+guint
+add_parameter_charset (proto_tree *tree, tvbuff_t *tvb, guint offset, guint startOffset)
+{
+ guint octet = tvb_get_guint8 (tvb, offset);
+ if (octet < 31)
+ {
+ offset += octet+1;
+ proto_tree_add_item (tree, hf_wsp_parameter_well_known_charset, tvb, startOffset+1, octet, bo_big_endian);
+ }
+ else if (octet & 0x80)
+ {
+ offset++;
+ proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset, tvb, startOffset, offset-startOffset, (octet & 0x7F));
+ }
+
+ return offset;
+}
+
+void
+add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType)
+{
+ guint offset = 0;
+ guint variableStart = 0;
+ guint variableEnd = 0;
+ guint valueStart = 0;
+ guint valueEnd = 0;
+ guint8 peek = 0;
+ proto_item *ti;
+
+ ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,END_OF_FRAME,bo_little_endian);
+
+ if (contentType == 0x12) /* URL Encoded data */
+ {
+ /* Iterate through post data */
+ for (offset = 0; offset < tvb_reported_length (tvb); offset++)
+ {
+ peek = tvb_get_guint8 (tvb, offset);
+ if (peek == '=')
+ {
+ variableEnd = offset-1;
+ valueStart = offset+1;
+ }
+ else if (peek == '&')
+ {
+ if (variableEnd > 0)
+ {
+ add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
+ }
+ variableStart = offset+1;
+ variableEnd = 0;
+ valueStart = 0;
+ valueEnd = 0;
+ }
+ }
+
+ /* See if there's outstanding data */
+ if (variableEnd > 0)
+ {
+ add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
+ }
+ }
+}
+
+void
+add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
+{
+ int variableLength = variableEnd-variableStart;
+ int valueLength = 0;
+ char *variableBuffer;
+ char *valueBuffer;
+
+ variableBuffer = g_malloc (variableLength+1);
+ strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength+1);
+ variableBuffer[variableLength+1] = 0;
+
+ if (valueEnd == 0)
+ {
+ valueBuffer = g_malloc (1);
+ valueBuffer[0] = 0;
+ valueEnd = valueStart;
+ }
+ else
+ {
+ valueLength = valueEnd-valueStart;
+ valueBuffer = g_malloc (valueLength+1);
+ strncpy (valueBuffer, tvb_get_ptr (tvb, valueStart, valueLength), valueLength);
+ valueBuffer[valueLength] = 0;
+ }
+
+ /* Check for variables with no value */
+ if (valueStart >= tvb_reported_length (tvb))
+ {
+ valueStart = tvb_reported_length (tvb);
+ valueEnd = valueStart;
+ }
+ valueLength = valueEnd-valueStart;
+
+ proto_tree_add_text (tree, tvb, variableStart, valueEnd-variableStart, "%s: %s", variableBuffer, valueBuffer);
+
+ g_free (variableBuffer);
+ g_free (valueBuffer);
+}
+
+/* Register the protocol with Ethereal */
+void
+proto_register_wsp(void)
+{
+
+/* Setup list of header fields */
+ static hf_register_info hf[] = {
+ { &hf_wsp_header_tid,
+ { "Transmission ID",
+ "wsp.TID",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ "Transmission ID"
+ }
+ },
+ { &hf_wsp_header_pdu_type,
+ { "PDU Type",
+ "wsp.pdu-type",
+ FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
+ "PDU Type"
+ }
+ },
+ { &hf_wsp_version_major,
+ { "Version (Major)",
+ "wsp.version.major",
+ FT_UINT8, BASE_DEC, NULL, 0xF0,
+ "Version (Major)"
+ }
+ },
+ { &hf_wsp_version_minor,
+ { "Version (Minor)",
+ "wsp.version.minor",
+ FT_UINT8, BASE_DEC, NULL, 0x0F,
+ "Version (Minor)"
+ }
+ },
+ { &hf_wsp_capability_length,
+ { "Capability Length",
+ "wsp.capability.length",
+ FT_UINT32, BASE_DEC, NULL, 0x00,
+ "Capability Length"
+ }
+ },
+ { &hf_wsp_header_length,
+ { "Headers Length",
+ "wsp.headers-length",
+ FT_UINT32, BASE_DEC, NULL, 0x00,
+ "Headers Length"
+ }
+ },
+ { &hf_wsp_capabilities_section,
+ { "Capabilities",
+ "wsp.capabilities",
+ FT_NONE, BASE_DEC, NULL, 0x00,
+ "Capabilities"
+ }
+ },
+ { &hf_wsp_headers_section,
+ { "Headers",
+ "wsp.headers",
+ FT_NONE, BASE_DEC, NULL, 0x00,
+ "Headers"
+ }
+ },
+ { &hf_wsp_header,
+ { "Header",
+ "wsp.headers.header",
+ FT_NONE, BASE_DEC, NULL, 0x00,
+ "Header"
+ }
+ },
+ { &hf_wsp_header_uri_len,
+ { "URI Length",
+ "wsp.uri-length",
+ FT_UINT32, BASE_DEC, NULL, 0x00,
+ "URI Length"
+ }
+ },
+ { &hf_wsp_header_uri,
+ { "URI",
+ "wsp.uri",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "URI"
+ }
+ },
+ { &hf_wsp_server_session_id,
+ { "Server Session ID",
+ "wsp.server.session-id",
+ FT_UINT32, BASE_DEC, NULL, 0x00,
+ "Server Session ID"
+ }
+ },
+ { &hf_wsp_header_status,
+ { "Status",
+ "wsp.reply.status",
+ FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
+ "Status"
+ }
+ },
+ { &hf_wsp_content_type,
+ { "Content Type",
+ "wsp.content-type.type",
+ FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
+ "Content Type"
+ }
+ },
+ { &hf_wsp_parameter_well_known_charset,
+ { "Charset",
+ "wsp.content-type.parameter.charset",
+ FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
+ "Charset"
+ }
+ },
+ { &hf_wsp_reply_data,
+ { "Data",
+ "wsp.reply.data",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ "Data"
+ }
+ },
+ { &hf_wsp_header_accept,
+ { "Accept",
+ "wsp.header.accept",
+ /*FT_NONE, BASE_DEC, NULL, 0x00,*/
+ FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
+ "Accept"
+ }
+ },
+ { &hf_wsp_header_accept_str,
+ { "Accept",
+ "wsp.header.accept.string",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Accept"
+ }
+ },
+ { &hf_wsp_header_accept_charset,
+ { "Accept-Charset",
+ "wsp.header.accept-charset",
+ FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
+ "Accept-Charset"
+ }
+ },
+ { &hf_wsp_header_accept_language,
+ { "Accept-Language",
+ "wsp.header.accept-language",
+ FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
+ "Accept-Language"
+ }
+ },
+ { &hf_wsp_header_accept_ranges,
+ { "Accept-Ranges",
+ "wsp.header.accept-ranges",
+ FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
+ "Accept-Ranges"
+ }
+ },
+ { &hf_wsp_header_age,
+ { "Age",
+ "wsp.header.age",
+ FT_UINT32, BASE_DEC, NULL, 0x00,
+ "Age"
+ }
+ },
+ { &hf_wsp_header_cache_control,
+ { "Cache-Control",
+ "wsp.header.cache-control",
+ FT_UINT8, BASE_HEX, VALS ( vals_cache_control ), 0x00,
+ "Cache-Control"
+ }
+ },
+ { &hf_wsp_header_content_length,
+ { "Content-Length",
+ "wsp.header.content-length",
+ FT_UINT32, BASE_DEC, NULL, 0x00,
+ "Content-Length"
+ }
+ },
+ { &hf_wsp_header_date,
+ { "Date",
+ "wsp.header.date",
+ FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
+ "Date"
+ }
+ },
+ { &hf_wsp_header_etag,
+ { "Etag",
+ "wsp.header.etag",
+ /*FT_NONE, BASE_DEC, NULL, 0x00,*/
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Etag"
+ }
+ },
+ { &hf_wsp_header_expires,
+ { "Expires",
+ "wsp.header.expires",
+ FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
+ "Expires"
+ }
+ },
+ { &hf_wsp_header_last_modified,
+ { "Last-Modified",
+ "wsp.header.last-modified",
+ FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
+ "Last-Modified"
+ }
+ },
+ { &hf_wsp_header_location,
+ { "Location",
+ "wsp.header.location",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Location"
+ }
+ },
+ { &hf_wsp_header_if_modified_since,
+ { "If-Modified-Since",
+ "wsp.header.if-modified-since",
+ FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
+ "If-Modified-Since"
+ }
+ },
+ { &hf_wsp_header_server,
+ { "Server",
+ "wsp.header.server",
+ /*FT_NONE, BASE_DEC, NULL, 0x00,*/
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Server"
+ }
+ },
+ { &hf_wsp_header_user_agent,
+ { "User-Agent",
+ "wsp.header.user-agent",
+ /*FT_NONE, BASE_DEC, NULL, 0x00,*/
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "User-Agent"
+ }
+ },
+ { &hf_wsp_header_application_header,
+ { "Application Header",
+ "wsp.header.application-header",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Application Header"
+ }
+ },
+ { &hf_wsp_header_application_value,
+ { "Application Header Value",
+ "wsp.header.application-header.value",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Application Header Value"
+ }
+ },
+ { &hf_wsp_header_x_wap_tod,
+ { "X-WAP.TOD",
+ "wsp.header.x_wap_tod",
+ FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
+ "X-WAP.TOD"
+ }
+ },
+ { &hf_wsp_post_data,
+ { "Post Data",
+ "wsp.post.data",
+ FT_NONE, BASE_NONE, NULL, 0x00,
+ "Post Data"
+ }
+ },
+ };
+
+/* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_wsp,
+ &ett_header,
+ &ett_headers,
+ &ett_capabilities,
+ &ett_content_type,
+ };
+
+/* Register the protocol name and description */
+ proto_wsp = proto_register_protocol(
+ "Wireless Session Protocol", /* protocol name for use by ethereal */
+ "wap-wsp" /* Abbreviated protocol name, should Match IANA
+ < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
+ */
+ );
+
+/* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_wsp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+};
+
+void
+proto_reg_handoff_wsp(void)
+{
+ /* Only connection-less WSP has no previous handler */
+// dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp_no_tvbuff);
+ dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp);
+ /* dissector_add("udp.port", UDP_PORT_WTP_WSP, dissect_wsp_no_tvbuff); */
+ /* dissector_add("udp.port", UDP_PORT_WTLS_WSP, dissect_wsp_no_tvbuff); */
+ /* dissector_add("udp.port", UDP_PORT_WTLS_WTP_WSP, dissect_wsp_no_tvbuff); */
+}