-/* packet-wsp.c (c) 2000 Neil Hunter
- * Based on original work by Ben Fowler
+/* packet-wsp.c
*
* Routines to dissect WSP component of WAP traffic.
*
- * $Id: packet-wsp.c,v 1.5 2000/12/02 08:41:08 guy Exp $
+ * $Id: packet-wsp.c,v 1.19 2001/02/19 21:02:33 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
* Copyright 1998 Didier Jorand
*
+ * WAP dissector based on original work by Ben Fowler
+ * Updated by Neil Hunter <neil.hunter@energis-squared.com>
+ * WTLS support by Alexandre P. Ferreira (Splice IP)
+ *
* 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
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_charset_str = HF_EMPTY;
static int hf_wsp_header_accept_language = HF_EMPTY;
+static int hf_wsp_header_accept_language_str = 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_application_header = HF_EMPTY;
static int hf_wsp_header_application_value = HF_EMPTY;
static int hf_wsp_header_x_wap_tod = HF_EMPTY;
+static int hf_wsp_header_transfer_encoding = HF_EMPTY;
+static int hf_wsp_header_transfer_encoding_str = HF_EMPTY;
+static int hf_wsp_header_via = HF_EMPTY;
/* Initialize the subtree pointers */
static gint ett_wsp = ETT_EMPTY;
static gint ett_capabilities = ETT_EMPTY;
static gint ett_content_type = ETT_EMPTY;
+/* Handle for WMLC dissector */
+static dissector_handle_t wmlc_handle;
+
static const value_string vals_pdu_type[] = {
{ 0x00, "Reserved" },
{ 0x01, "Connect" },
/* 0x70 - 0x7F Extended method (Post PDU) */
/* 0x80 - 0xFF Reserved */
+ { 0x00, NULL }
+
};
static const value_string vals_status[] = {
{ 0x63, "Service Unavailable" },
{ 0x64, "Gateway Timeout" },
{ 0x65, "HTTP Version Not Supported" },
+ { 0x00, NULL }
};
static const value_string vals_content_types[] = {
{ 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" },
+ { 0x00, NULL }
};
static const value_string vals_languages[] = {
+ { 0x01, "Afar (aa)" },
+ { 0x02, "Abkhazian (ab)" },
+ { 0x03, "Afrikaans (af)" },
+ { 0x04, "Amharic (am)" },
+ { 0x05, "Arabic (ar)" },
+ { 0x06, "Assamese (as)" },
+ { 0x07, "Aymara (ay)" },
+ { 0x08, "Azerbaijani (az)" },
+ { 0x09, "Bashkir (ba)" },
+ { 0x0A, "Byelorussian (be)" },
+ { 0x0B, "Bulgarian (bg)" },
+ { 0x0C, "Bihari (bh)" },
+ { 0x0D, "Bislama (bi)" },
+ { 0x0E, "Bengali; Bangla (bn)" },
+ { 0x0F, "Tibetan (bo)" },
+ { 0x10, "Breton (br)" },
+ { 0x11, "Catalan (ca)" },
+ { 0x12, "Corsican (co)" },
+ { 0x13, "Czech (cs)" },
+ { 0x14, "Welsh (cy)" },
+ { 0x15, "Danish (da)" },
+ { 0x16, "German (de)" },
+ { 0x17, "Bhutani (dz)" },
+ { 0x18, "Greek (el)" },
{ 0x19, "English (en)" },
+ { 0x1A, "Esperanto (eo)" },
+ { 0x1B, "Spanish (es)" },
+ { 0x1C, "Estonian (et)" },
+ { 0x1D, "Basque (eu)" },
+ { 0x1E, "Persian (fa)" },
+ { 0x1F, "Finnish (fi)" },
+ { 0x20, "Fiji (fj)" },
+ { 0x22, "French (fr)" },
+ { 0x24, "Irish (ga)" },
+ { 0x25, "Scots Gaelic (gd)" },
+ { 0x26, "Galician (gl)" },
+ { 0x27, "Guarani (gn)" },
+ { 0x28, "Gujarati (gu)" },
+ { 0x29, "Hausa (ha)" },
+ { 0x2A, "Hebrew (formerly iw) (he)" },
+ { 0x2B, "Hindi (hi)" },
+ { 0x2C, "Croatian (hr)" },
+ { 0x2D, "Hungarian (hu)" },
+ { 0x2E, "Armenian (hy)" },
+ { 0x30, "Indonesian (formerly in) (id)" },
+ { 0x47, "Maori (mi)" },
+ { 0x48, "Macedonian (mk)" },
+ { 0x49, "Malayalam (ml)" },
+ { 0x4A, "Mongolian (mn)" },
+ { 0x4B, "Moldavian (mo)" },
+ { 0x4C, "Marathi (mr)" },
+ { 0x4D, "Malay (ms)" },
+ { 0x4E, "Maltese (mt)" },
+ { 0x4F, "Burmese (my)" },
+ { 0x51, "Nepali (ne)" },
+ { 0x52, "Dutch (nl)" },
+ { 0x53, "Norwegian (no)" },
+ { 0x54, "Occitan (oc)" },
+ { 0x55, "(Afan) Oromo (om)" },
+ { 0x56, "Oriya (or)" },
+ { 0x57, "Punjabi (pa)" },
+ { 0x58, "Polish (po)" },
+ { 0x59, "Pashto, Pushto (ps)" },
+ { 0x5A, "Portuguese (pt)" },
+ { 0x5B, "Quechua (qu)" },
+ { 0x5D, "Kirundi (rn)" },
+ { 0x5E, "Romanian (ro)" },
+ { 0x5F, "Russian (ru)" },
+ { 0x60, "Kinyarwanda (rw)" },
+ { 0x61, "Sanskrit (sa)" },
+ { 0x62, "Sindhi (sd)" },
+ { 0x63, "Sangho (sg)" },
+ { 0x64, "Serbo-Croatian (sh)" },
+ { 0x65, "Sinhalese (si)" },
+ { 0x66, "Slovak (sk)" },
+ { 0x67, "Slovenian (sl)" },
+ { 0x68, "Samoan (sm)" },
+ { 0x69, "Shona (sn)" },
+ { 0x6A, "Somali (so)" },
+ { 0x6B, "Albanian (sq)" },
+ { 0x6C, "Serbian (sr)" },
+ { 0x6D, "Siswati (ss)" },
+ { 0x6E, "Sesotho (st)" },
+ { 0x6F, "Sundanese (su)" },
+ { 0x70, "Swedish (sv)" },
+ { 0x71, "Swahili (sw)" },
+ { 0x72, "Tamil (ta)" },
+ { 0x73, "Telugu (te)" },
+ { 0x74, "Tajik (tg)" },
+ { 0x75, "Thai (th)" },
+ { 0x76, "Tigrinya (ti)" },
+ { 0x81, "Nauru (na)" },
+ { 0x82, "Faeroese (fo)" },
+ { 0x83, "Frisian (fy)" },
+ { 0x84, "Interlingua (ia)" },
+ { 0x8C, "Rhaeto-Romance (rm)" },
+ { 0x00, NULL }
};
static const value_string vals_accept_ranges[] = {
{ 0x80, "None" },
{ 0x81, "Bytes" },
+ { 0x00, NULL }
};
static const value_string vals_cache_control[] = {
{ 0x88, "No-transform" },
{ 0x89, "Must-revalidate" },
{ 0x8A, "Proxy-revalidate" },
+ { 0x00, NULL }
+};
+
+static const value_string vals_transfer_encoding[] = {
+ { 0x80, "Chunked" },
+ { 0x00, NULL }
};
/*
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);
-}
+static void add_uri (proto_tree *, tvbuff_t *, guint, guint);
+static void add_headers (proto_tree *, tvbuff_t *);
+static void add_header (proto_tree *, tvbuff_t *, tvbuff_t *);
+static guint get_value_length (tvbuff_t *, guint, guint *);
+static guint add_content_type (proto_tree *, tvbuff_t *, guint, guint *);
+static gint get_date_value (tvbuff_t * ,guint ,struct timeval *);
+static void add_date_value (tvbuff_t * ,guint ,proto_tree * ,int ,
+ tvbuff_t * ,guint ,guint ,struct timeval *, const char *);
+static guint add_parameter (proto_tree *, tvbuff_t *, guint);
+static guint add_parameter_charset (proto_tree *, tvbuff_t *, guint, guint);
+static void add_post_data (proto_tree *, tvbuff_t *, guint);
+static void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
/* Code to actually dissect the packets */
-void
+static 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;
+ guint8 pdut;
guint count = 0;
guint value = 0;
guint uriLength = 0;
/* proto_tree *wsp_header_fixed; */
proto_tree *wsp_capabilities;
- CHECK_DISPLAY_AS_DATA(proto_wsp, tvb, pinfo, tree);
-
- pinfo->current_proto = "WSP";
-
/* 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. */
}
}
+ /* Clear the Info column before we fetch anything from the packet */
+ if (check_col(fdata, COL_INFO))
+ {
+ col_clear(fdata, COL_INFO);
+ }
+
/* Connection-less mode has a TID first */
- if ((pinfo->match_port == UDP_PORT_WSP) || (pinfo->match_port == UDP_PORT_WTLS_WSP))
+ if ( (pinfo->match_port == UDP_PORT_WSP) ||
+ (pinfo->match_port == UDP_PORT_WTLS_WSP))
{
offset++;
};
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 );
+ if (check_col(fdata, COL_INFO))
+ {
+ col_add_fstr(fdata, COL_INFO, "WSP %s",
+ val_to_str (pdut, vals_pdu_type, "Unknown PDU type (0x%02x)"));
};
/* In the interest of speed, if "tree" is NULL, don't do any work not
/* Code to process the packet goes here */
/*
- wsp_header_fixed = proto_item_add_subtree(
- ti,
- ett_header
- );
+ 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))
+ /* If this is connectionless, then the TID Field is always first */
+ 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, hf_wsp_header_tid,tvb,
+ 0,1,bo_little_endian);
}
ti = proto_tree_add_item(
ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
offset++;
capabilityStart = offset;
+ count = 0; /* Initialise count */
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;
+ count = 0; /* Initialise count */
headerLength = tvb_get_guintvar (tvb, offset, &count);
offset += count;
ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
break;
case CONNECTREPLY:
+ count = 0; /* Initialise count */
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;
+ count = 0; /* Initialise count */
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;
+ count = 0; /* Initialise count */
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);
+ 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);
break;
case DISCONNECT:
+ count = 0; /* Initialise count */
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:
+ count = 0; /* Initialise count */
/* 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);
+ offset += (value+count); /* VERIFY */
tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
add_headers (wsp_tree, tmp_tvb);
break;
case POST:
uriStart = offset;
+ count = 0; /* Initialise count */
uriLength = tvb_get_guintvar (tvb, offset, &count);
headerStart = uriStart+count;
+ count = 0; /* Initialise count */
headersLength = tvb_get_guintvar (tvb, headerStart, &count);
offset = headerStart + count;
case REPLY:
ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
+ count = 0; /* Initialise count */
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);
+ ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,value);
contentTypeStart = nextOffset;
nextOffset = add_content_type (wsp_tree, tvb, nextOffset, &contentType);
}
}
-void
+static void
add_uri (proto_tree *tree, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
{
proto_item *ti;
}
}
-void
+static void
add_headers (proto_tree *tree, tvbuff_t *tvb)
{
proto_item *ti;
#ifdef DEBUG
fprintf (stderr, "dissect_wsp: Looking for %d octets\n", peek);
#endif
- valueStart++;
+ /* VERIFY: valueStart++; */
valueEnd = offset+1+peek;
offset += (peek+1);
}
#ifdef DEBUG
fprintf (stderr, "dissect_wsp: Looking for uintvar octets\n");
#endif
+ count = 0; /* Initialise count */
tvb_get_guintvar (tvb, valueStart, &count);
valueEnd = offset+1+count;
offset += (count+1);
}
}
-void
+static void
add_header (proto_tree *tree, tvbuff_t *header_buff, tvbuff_t *value_buff)
{
guint offset = 0;
+ guint valueStart = 0;
guint8 headerType = 0;
proto_item *ti;
guint headerLen = tvb_reported_length (header_buff);
guint peek = 0;
struct timeval timeValue;
guint value = 0;
+ guint valueLength = 0;
+ char valString[100];
+ char *valMatch = NULL;
+ double q_value = 1.0;
+
+ /* Initialise time values */
+ timeValue.tv_sec=0;
+ timeValue.tv_usec = 0;
headerType = tvb_get_guint8 (header_buff, 0);
peek = tvb_get_guint8 (value_buff, 0);
break;
case 0x01: /* Accept-Charset */
+ if (peek <= 31) /* Accept-charset-general-form */
+ {
+ /* Get Value-Length */
+ valueLength = get_value_length (value_buff, offset,
+ &valueStart);
+ offset = valueStart;
+
+ peek = tvb_get_guint8 (value_buff, offset);
+ if ((peek >= 0x80) || (peek <= 30)) /* Well-known-charset */
+ {
+ if (peek == 0x80) /* Any */
+ {
+ value = peek;
+ offset++;
+ }
+ else if (peek & 0x80) /* Short-Integer */
+ {
+ value = peek & 0x7F;
+ offset++;
+ }
+ else if (peek <= 30) /* Long-Integer */
+ {
+ offset++;
+
+ switch (peek)
+ {
+ case 1:
+ value = tvb_get_guint8 (value_buff, offset);
+ break;
+ case 2:
+ value = tvb_get_ntohs (value_buff, offset);
+ break;
+ case 3:
+ value = tvb_get_ntoh24 (value_buff, offset);
+ break;
+ case 4:
+ value = tvb_get_ntohl (value_buff, offset);
+ break;
+ default:
+ /* TODO: Need to read peek octets */
+ value = 0;
+ fprintf (stderr, "dissect_wsp: accept-charset size %d NYI\n", peek);
+ break;
+ }
+ offset += peek;
+ }
+ valMatch = match_strval(value, vals_character_sets);
+ }
+ else /* Assume Token-text */
+ {
+ fprintf (stderr, "dissect_wsp: Accept-Charset Token-text NYI\n");
+ }
+
+ /* Any remaining data relates to Q-Value */
+ if (offset < valueLen)
+ {
+ peek = tvb_get_guintvar (value_buff, offset, NULL);
+ if (peek <= 100) {
+ peek = (peek - 1) * 10;
+ }
+ else {
+ peek -= 100;
+ }
+ q_value = peek/1000.0;
+ }
+
+ /* Build string including Q values if present */
+ if (q_value == 1.0) /* Default */
+ {
+ if (valMatch == NULL)
+ {
+ snprintf (valString, 100, "Unknown (%X)", peek);
+ }
+ else
+ {
+ snprintf (valString, 100, "%s", valMatch);
+ }
+ }
+ else
+ {
+ if (valMatch == NULL)
+ {
+ snprintf (valString, 100, "Unknown (%X); Q=%5.3f", peek,q_value);
+ }
+ else
+ {
+ snprintf (valString, 100, "%s; Q=%5.3f", valMatch,q_value);
+ }
+ }
+
+ /* Add string to tree */
+ proto_tree_add_string (tree, hf_wsp_header_accept_charset_str,
+ header_buff, 0, headerLen, valString);
+ }
+ else /* Constrained-charset */
+ {
+ if (peek == 0x80) /* Any-charset */
+ {
+ proto_tree_add_string (tree, hf_wsp_header_accept_charset,
+ header_buff, offset, headerLen,
+ "*");
+ }
+ else if (peek & 0x80) /* Short-Integer */
+ {
+ proto_tree_add_uint (tree, hf_wsp_header_accept_charset,
+ header_buff, offset, headerLen, (peek & 0x7F) );
+ }
+ else /* Assume *TEXT */
+ {
+ proto_tree_add_string (tree, hf_wsp_header_accept_charset,
+ header_buff, offset, headerLen,
+ tvb_get_ptr (value_buff, 0, valueLen));
+ }
+ }
+ break;
+
+ case 0x03: /* Accept-Language */
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;
+ proto_tree_add_uint (tree, hf_wsp_header_accept_language, 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;
+ proto_tree_add_uint (tree, hf_wsp_header_accept_language, 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;
+ proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset,
+ headerLen, tvb_get_ntohl (value_buff, 1) );
+ break;
default:
- fprintf (stderr, "dissect_wsp: accept-charset size %d NYI\n", peek);
+ fprintf (stderr, "dissect_wsp: accept-language 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) );
+ proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, headerLen, (peek & 0x7F) );
}
else
{
- fprintf (stderr, "dissect_wsp: Accept-Charset value %d (0x%02X) NYI\n", peek, peek);
+ proto_tree_add_string (tree, hf_wsp_header_accept_language_str, header_buff, offset,headerLen,
+ tvb_get_ptr (value_buff, 0, valueLen));
}
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))
{
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);
+ proto_tree_add_text (tree, header_buff, 0,
+ headerLen, "Cache-Control: %s %d (0x%02X)",
+ val_to_str (peek, vals_cache_control,
+ "Unknown (0x%02x)"),
+ (value & 0x7F), peek);
}
else
{
break;
case 0x0D: /* Content-Length */
- if (peek & 0x80)
+ if (peek < 31)
+ {
+ switch (peek)
+ {
+ case 1:
+ proto_tree_add_uint (tree,
+ hf_wsp_header_content_length, header_buff, offset,
+ headerLen, tvb_get_guint8 (value_buff, 1) );
+ break;
+ case 2:
+ proto_tree_add_uint (tree,
+ hf_wsp_header_content_length, header_buff, offset,
+ headerLen, tvb_get_ntohs (value_buff, 1) );
+ break;
+ case 3:
+ proto_tree_add_uint (tree,
+ hf_wsp_header_content_length, header_buff, offset,
+ headerLen, (tvb_get_ntohs (value_buff, 1) << 8) +
+ tvb_get_guint8 (value_buff, 3) );
+ break;
+ case 4:
+ proto_tree_add_uint (tree,
+ hf_wsp_header_content_length, 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_content_length, header_buff, offset, headerLen, (peek & 0x7F));
}
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);
+ add_date_value (value_buff, 0, tree,
+ hf_wsp_header_date, header_buff, offset,
+ headerLen, &timeValue, "Date");
break;
case 0x13: /* Etag */
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);
+ add_date_value (value_buff, 0, tree,
+ hf_wsp_header_expires, header_buff, offset,
+ headerLen, &timeValue, "Expires");
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);
+ add_date_value (value_buff, 0, tree,
+ hf_wsp_header_if_modified_since, header_buff, offset,
+ headerLen, &timeValue, "If-Modified-Since");
break;
case 0x1C: /* Location */
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);
+ add_date_value (value_buff, 0, tree,
+ hf_wsp_header_last_modified, header_buff, offset,
+ headerLen, &timeValue, "Last-Modified");
break;
case 0x1F: /* Pragma */
ti = proto_tree_add_string (tree, hf_wsp_header_server,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
break;
+ case 0x27: /* Transfer encoding */
+ if (peek & 0x80)
+ {
+ proto_tree_add_uint (tree, hf_wsp_header_transfer_encoding,
+ header_buff, offset, headerLen, peek);
+ }
+ else
+ {
+ proto_tree_add_string (tree,
+ hf_wsp_header_transfer_encoding_str, 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;
+ case 0x2B: /* Via */
+ ti = proto_tree_add_string (tree, hf_wsp_header_via, 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;
* 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 */
+ peek = tvb_get_guint8 (value_buff,offset);
+ if (peek < 31)
{
- timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
+ timeValue.tv_usec = 0;
+ switch (peek)
+ {
+ case 1:
+ timeValue.tv_sec = tvb_get_guint8 (value_buff, 1);
+ break;
+ case 2:
+ timeValue.tv_sec = tvb_get_ntohs (value_buff, 1);
+ break;
+ case 3:
+ timeValue.tv_sec = tvb_get_ntoh24 (value_buff, 1);
+ break;
+ case 4:
+ timeValue.tv_sec = tvb_get_ntohl (value_buff, 1);
+ break;
+ default:
+ timeValue.tv_sec = 0;
+ fprintf (stderr, "dissect_wsp: X-WAP.TOD NYI\n");
+ break;
+ }
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));
+ {
+ fprintf (stderr, "dissect_wsp: X-WAP.TOD peek %X NYI\n",peek);
}
}
else
}
-guint
+static guint
get_value_length (tvbuff_t *tvb, guint offset, guint *nextOffset)
{
guint value = 0;
return (value);
}
-guint
+static guint
add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset, guint *contentType)
{
proto_tree *contentTypeTree;
return (offset+totalSizeOfField);
}
-guint
+/* Utility function to extract date values from the packet */
+static gint
+get_date_value (tvbuff_t *buffer, guint offset, struct timeval *timeValue)
+{
+ guint ShortLength = 0;
+
+ /* Initialise time values */
+ timeValue->tv_sec=0;
+ timeValue->tv_usec = 0;
+
+ /* Date values are encoded as: Short-length Multi-octet-integer
+ * Where Short-length = 0-30
+ */
+ ShortLength = tvb_get_guint8 (buffer, offset++);
+ if (ShortLength > 30)
+ {
+ fprintf (stderr, "dissect_wsp: Invalid Date-value (Short-length=%d)\n",
+ ShortLength);
+ return (-1);
+ }
+
+ switch (ShortLength)
+ {
+ case 1:
+ timeValue->tv_sec = tvb_get_guint8 (buffer, offset);
+ break;
+ case 2:
+ timeValue->tv_sec = tvb_get_ntohs (buffer, offset);
+ break;
+ case 3:
+ timeValue->tv_sec = tvb_get_ntoh24 (buffer, offset);
+ break;
+ case 4:
+ timeValue->tv_sec = tvb_get_ntohl (buffer, offset);
+ break;
+ default:
+ fprintf (stderr, "dissect_wsp: Date-value Short-length of %d NYI\n",
+ ShortLength);
+ return (-1);
+ break;
+ }
+
+ return (0);
+}
+
+/* Utility function to add a date value to the protocol tree */
+static void
+add_date_value (tvbuff_t *buffer, guint offset, proto_tree *tree,
+ int header, tvbuff_t *headerBuffer, guint headerOffset,
+ guint headerLen, struct timeval *timeValue, const char *fieldName)
+{
+ /* Attempt to get the date value from the buffer */
+ if (get_date_value (buffer, offset, timeValue) == 0)
+ {
+ /* If successful, add it to the protocol tree */
+ proto_tree_add_time (tree, header, headerBuffer, headerOffset,
+ headerLen, timeValue);
+ }
+ else
+ {
+ fprintf (stderr, "dissect_wsp: Invalid %s value\n", fieldName);
+ }
+}
+
+static guint
add_parameter (proto_tree *tree, tvbuff_t *tvb, guint offset)
{
guint octet = tvb_get_guint8 (tvb, offset);
return (offset);
}
-guint
+static guint
add_parameter_charset (proto_tree *tree, tvbuff_t *tvb, guint offset, guint startOffset)
{
guint octet = tvb_get_guint8 (tvb, offset);
return offset;
}
-void
+static void
add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType)
{
guint offset = 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);
+ /* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,END_OF_FRAME,bo_little_endian); */
+ ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_reported_length(tvb),bo_little_endian);
if (contentType == 0x12) /* URL Encoded data */
{
peek = tvb_get_guint8 (tvb, offset);
if (peek == '=')
{
- variableEnd = offset-1;
+ variableEnd = offset;
valueStart = offset+1;
}
else if (peek == '&')
}
}
-void
+static void
add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
{
int variableLength = variableEnd-variableStart;
char *valueBuffer;
variableBuffer = g_malloc (variableLength+1);
- strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength+1);
- variableBuffer[variableLength+1] = 0;
+ strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength);
+ variableBuffer[variableLength] = 0;
- if (valueEnd == 0)
+ if (valueEnd < valueStart)
{
valueBuffer = g_malloc (1);
valueBuffer[0] = 0;
},
{ &hf_wsp_header_pdu_type,
{ "PDU Type",
- "wsp.pdu-type",
+ "wsp.pdu_type",
FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
"PDU Type"
}
},
{ &hf_wsp_header_length,
{ "Headers Length",
- "wsp.headers-length",
+ "wsp.headers_length",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Headers Length"
}
},
{ &hf_wsp_header_uri_len,
{ "URI Length",
- "wsp.uri-length",
+ "wsp.uri_length",
FT_UINT32, BASE_DEC, NULL, 0x00,
"URI Length"
}
},
{ &hf_wsp_server_session_id,
{ "Server Session ID",
- "wsp.server.session-id",
+ "wsp.server.session_id",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Server Session ID"
}
},
{ &hf_wsp_content_type,
{ "Content Type",
- "wsp.content-type.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",
+ "wsp.content_type.parameter.charset",
FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
"Charset"
}
},
{ &hf_wsp_header_accept_charset,
{ "Accept-Charset",
- "wsp.header.accept-charset",
+ "wsp.header.accept_charset",
FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
"Accept-Charset"
}
},
+ { &hf_wsp_header_accept_charset_str,
+ { "Accept-Charset",
+ "wsp.header.accept_charset.string",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Accept-Charset"
+ }
+ },
{ &hf_wsp_header_accept_language,
{ "Accept-Language",
- "wsp.header.accept-language",
+ "wsp.header.accept_language",
FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
"Accept-Language"
}
},
+ { &hf_wsp_header_accept_language_str,
+ { "Accept-Language",
+ "wsp.header.accept_language.string",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Accept-Language"
+ }
+ },
{ &hf_wsp_header_accept_ranges,
{ "Accept-Ranges",
- "wsp.header.accept-ranges",
+ "wsp.header.accept_ranges",
FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
"Accept-Ranges"
}
},
{ &hf_wsp_header_cache_control,
{ "Cache-Control",
- "wsp.header.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",
+ "wsp.header.content_length",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Content-Length"
}
},
{ &hf_wsp_header_last_modified,
{ "Last-Modified",
- "wsp.header.last-modified",
+ "wsp.header.last_modified",
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
"Last-Modified"
}
},
{ &hf_wsp_header_if_modified_since,
{ "If-Modified-Since",
- "wsp.header.if-modified-since",
+ "wsp.header.if_modified_since",
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
"If-Modified-Since"
}
"Server"
}
},
+ { &hf_wsp_header_transfer_encoding,
+ { "Transfer Encoding",
+ "wsp.header.transfer_enc",
+ /*FT_NONE, BASE_DEC, NULL, 0x00,*/
+ FT_UINT8, BASE_HEX, VALS ( vals_transfer_encoding ), 0x00,
+ "Transfer Encoding"
+ }
+ },
+ { &hf_wsp_header_transfer_encoding_str,
+ { "Transfer Encoding",
+ "wsp.header.transfer_enc_str",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Transfer Encoding"
+ }
+ },
{ &hf_wsp_header_user_agent,
{ "User-Agent",
- "wsp.header.user-agent",
+ "wsp.header.user_agent",
/*FT_NONE, BASE_DEC, NULL, 0x00,*/
FT_STRING, BASE_NONE, NULL, 0x00,
"User-Agent"
}
},
+ { &hf_wsp_header_via,
+ { "Via",
+ "wsp.header.via",
+ FT_STRING, BASE_NONE, NULL, 0x00,
+ "Via"
+ }
+ },
{ &hf_wsp_header_application_header,
{ "Application Header",
- "wsp.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",
+ "wsp.header.application_header.value",
FT_STRING, BASE_NONE, NULL, 0x00,
"Application Header Value"
}
/* Register the protocol name and description */
proto_wsp = proto_register_protocol(
"Wireless Session Protocol", /* protocol name for use by ethereal */
+ "WSP", /* short version of name */
"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));
+
+ register_dissector("wsp", dissect_wsp, proto_wsp);
};
void
proto_reg_handoff_wsp(void)
{
+ /*
+ * Get a handle for the WMLC dissector
+ */
+ wmlc_handle = find_dissector("wmlc"); /* Coming soon :) */
+
/* Only connection-less WSP has no previous handler */
- dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp);
- /* dissector_add("udp.port", UDP_PORT_WTP_WSP, dissect_wsp); */
- /* dissector_add("udp.port", UDP_PORT_WTLS_WSP, dissect_wsp); */
- /* dissector_add("udp.port", UDP_PORT_WTLS_WTP_WSP, dissect_wsp); */
+ dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp, proto_wsp);
+
+ /* This dissector is also called from the WTP and WTLS dissectors */
}