wireshark/packet-wsp.c

2194 lines
60 KiB
C
Raw Normal View History

/* packet-wsp.c
*
* Routines to dissect WSP component of WAP traffic.
*
* $Id: packet-wsp.c,v 1.23 2001/07/03 09:53:21 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* 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
* 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_capabilities_client_SDU = HF_EMPTY;
static int hf_wsp_capabilities_server_SDU = HF_EMPTY;
static int hf_wsp_capabilities_protocol_opt = HF_EMPTY;
static int hf_wsp_capabilities_method_MOR = HF_EMPTY;
static int hf_wsp_capabilities_push_MOR = HF_EMPTY;
static int hf_wsp_capabilities_extended_methods = HF_EMPTY;
static int hf_wsp_capabilities_header_code_pages = HF_EMPTY;
static int hf_wsp_capabilities_aliases = 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_shift_code = 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_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_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;
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_header = ETT_EMPTY;
static gint ett_headers = 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" },
{ 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 */
{ 0x00, NULL }
};
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" },
{ 0x00, NULL }
};
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" },
{ 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[] = {
{ 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" },
{ 0x00, NULL }
};
static const value_string vals_transfer_encoding[] = {
{ 0x80, "Chunked" },
{ 0x00, NULL }
};
/*
* Windows appears to define DELETE.
*/
#ifdef DELETE
#undef DELETE
#endif
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 */
};
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);
static gint get_long_integer (tvbuff_t *, guint *, guint , guint *);
static void add_capabilities (proto_tree *tree, tvbuff_t *tvb);
static guint get_uintvar (tvbuff_t *, guint, guint);
/* Code to actually dissect the packets */
static void
dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
frame_data *fdata = pinfo->fd;
int offset = 0;
guint8 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; */
/* 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))
{
Remove more "CHECK_DISPLAY_AS_DATA()" calls and "pinfo->current_proto =" statements. Move the setting of the Protocol column in various dissectors before anything is fetched from the packet, and also clear the Info column at that point in those and some other dissectors, so that if an exception is thrown, the columns don't reflect the previous protocol. Don't use col_add_fstr(..., "%s", string); Use col_add_str(..., string); as it does the same thing, but doesn't drag all the heavy *printf machinery in. Fix the DDTP dissector to set the Info column regardless of whether we're building a protocol tree or not, and to set it to "Encrypted payload" if the payload is encrypted. Also fix a typo in a field name. Register the FTP data dissector as being associated with the FTP data protocol, not the FTP protocol (the removed "CHECK_DISPLAY_AS_DATA()" call checked "proto_ftp_data", and the removed "pinfo->current_proto =" line set it to "FTP-DATA", so it should be associated with "proto_ftp_data"). Make the H1 dissector check whether the frame has at least 2 bytes in it before checking the first two bytes; heuristic dissectors must not throw exceptions until they've accepted the packet as one of theirs. Use "tvb_format_text()" rather than "tvb_get_ptr()" and "format_text()" in some dissectors where the result of "tvb_get_ptr()" is used only in the "format_text()" call. In the Quake dissector, don't check whether there are at least 4 bytes in the packet - if we return, the packet won't be dissected at all (it's not as if some other dissector will get to handle it), and, if we don't return, we'll throw an exception if there aren't at least 4 bytes in the packet, so the packet will be marked as short or malformed, as appropriate. In the RIPng dissector, associate the table of strings for the command field with the command field, so that the dissector doesn't have to format the string for the protocol tree entry itself, and so that the filter construction dialog box can let you select "Request" or "Response" from a list rather than requiring you to know the values for "Request" and "Response". Make "dissect_rpc()" static, as it's called only through a heuristic dissector list. Use "col_set_str()" to set the COL_PROTOCOL column for RPC protocols; the string used is from a table provided by the dissector, and is a string constant. Don't format the Info column for WSP into a buffer and then format that buffer into the column with "%s" - "col_add_fstr()" can do the formatting for you, without having to allocate your own buffer (or run through the *printf machinery twice). Don't fetch fields from the WTP packet until you're ready to use them, so that you don't throw an exception before you even set the Protocol column or clear the Info column. Use "pinfo->destport", not "pi.destport", in the Zebra dissector when checking whether the packet is a request or reply, and do the check by comparing with "pinfo->match_port" rather than TCP_PORT_ZEBRA (so that if the dissector is ever registered on another port, it still correctly determines whether the packet is a request or reply - the Network Monitor HTTP dissector has port 80 wired into its brain, which is a bit irritating if you're trying to get it to dissect HTTP proxy traffic on port 3128 or proxy administration UI traffic on port 3132). svn path=/trunk/; revision=2931
2001-01-22 08:03:46 +00:00
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))
{
offset++;
};
/* Find the PDU type */
pdut = tvb_get_guint8 (tvb, offset);
/* Develop the string to put in the Info column */
if (check_col(fdata, COL_INFO))
{
Remove more "CHECK_DISPLAY_AS_DATA()" calls and "pinfo->current_proto =" statements. Move the setting of the Protocol column in various dissectors before anything is fetched from the packet, and also clear the Info column at that point in those and some other dissectors, so that if an exception is thrown, the columns don't reflect the previous protocol. Don't use col_add_fstr(..., "%s", string); Use col_add_str(..., string); as it does the same thing, but doesn't drag all the heavy *printf machinery in. Fix the DDTP dissector to set the Info column regardless of whether we're building a protocol tree or not, and to set it to "Encrypted payload" if the payload is encrypted. Also fix a typo in a field name. Register the FTP data dissector as being associated with the FTP data protocol, not the FTP protocol (the removed "CHECK_DISPLAY_AS_DATA()" call checked "proto_ftp_data", and the removed "pinfo->current_proto =" line set it to "FTP-DATA", so it should be associated with "proto_ftp_data"). Make the H1 dissector check whether the frame has at least 2 bytes in it before checking the first two bytes; heuristic dissectors must not throw exceptions until they've accepted the packet as one of theirs. Use "tvb_format_text()" rather than "tvb_get_ptr()" and "format_text()" in some dissectors where the result of "tvb_get_ptr()" is used only in the "format_text()" call. In the Quake dissector, don't check whether there are at least 4 bytes in the packet - if we return, the packet won't be dissected at all (it's not as if some other dissector will get to handle it), and, if we don't return, we'll throw an exception if there aren't at least 4 bytes in the packet, so the packet will be marked as short or malformed, as appropriate. In the RIPng dissector, associate the table of strings for the command field with the command field, so that the dissector doesn't have to format the string for the protocol tree entry itself, and so that the filter construction dialog box can let you select "Request" or "Response" from a list rather than requiring you to know the values for "Request" and "Response". Make "dissect_rpc()" static, as it's called only through a heuristic dissector list. Use "col_set_str()" to set the COL_PROTOCOL column for RPC protocols; the string used is from a table provided by the dissector, and is a string constant. Don't format the Info column for WSP into a buffer and then format that buffer into the column with "%s" - "col_add_fstr()" can do the formatting for you, without having to allocate your own buffer (or run through the *printf machinery twice). Don't fetch fields from the WTP packet until you're ready to use them, so that you don't throw an exception before you even set the Protocol column or clear the Info column. Use "pinfo->destport", not "pi.destport", in the Zebra dissector when checking whether the packet is a request or reply, and do the check by comparing with "pinfo->match_port" rather than TCP_PORT_ZEBRA (so that if the dissector is ever registered on another port, it still correctly determines whether the packet is a request or reply - the Network Monitor HTTP dissector has port 80 wired into its brain, which is a bit irritating if you're trying to get it to dissect HTTP proxy traffic on port 3128 or proxy administration UI traffic on port 3132). svn path=/trunk/; revision=2931
2001-01-22 08:03:46 +00:00
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
necessary to generate protocol tree items. */
if (tree) {
ti = proto_tree_add_item(tree, proto_wsp, tvb, 0,
tvb_length(tvb), 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 */
/* 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, /* 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;
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);
if (capabilityLength > 0)
{
tmp_tvb = tvb_new_subset (tvb, offset, capabilityLength, capabilityLength);
add_capabilities (wsp_tree, tmp_tvb);
offset += capabilityLength;
}
if (headerLength > 0)
{
tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
add_headers (wsp_tree, tmp_tvb);
}
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_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
if (capabilityLength > 0)
{
tmp_tvb = tvb_new_subset (tvb, offset, capabilityLength, capabilityLength);
add_capabilities (wsp_tree, tmp_tvb);
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:
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+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;
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);
count = 0; /* Initialise count */
value = tvb_get_guintvar (tvb, offset+1, &count);
nextOffset = offset + 1 + count;
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);
/* 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,tvb_length_remaining(tvb, offset),bo_little_endian);
}
break;
}
}
}
/*
* Called directly from UDP.
* Put "WSP" into the "Protocol" column.
*/
static void
dissect_wsp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
if (check_col(pinfo->fd, COL_PROTOCOL))
col_set_str(pinfo->fd, COL_PROTOCOL, "WSP" );
dissect_wsp_common(tvb, pinfo, tree);
}
/*
* Called from a higher-level WAP dissector.
* Leave the "Protocol" column alone - the dissector calling us should
* have set it.
*/
static void
dissect_wsp_fromwap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
dissect_wsp_common(tvb, pinfo, tree);
}
static 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);
}
}
static 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;
guint pageCode = 1;
#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 */
{
pageCode = peek;
proto_tree_add_uint (wsp_headers, hf_wsp_header_shift_code, tvb , offset, 1, peek);
offset+=1;
continue;
}
else if (peek == 0x7F) /* Shift delimeter */
{
pageCode = tvb_get_guint8(tvb,offset+1);
proto_tree_add_uint (wsp_headers, hf_wsp_header_shift_code, tvb , offset, 2, pageCode);
offset+=2;
continue;
}
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
/* VERIFY: valueStart++; */
valueEnd = offset+1+peek;
offset += (peek+1);
}
else if (peek == 31)
{
#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);
}
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
if (pageCode == 1)
{
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);
}
else
{
proto_tree_add_text (wsp_headers, tvb , headerStart, valueEnd-headerStart,
"Unsupported Header (0x%02X)", (tvb_get_guint8 (tvb, headerStart) & 0x7F));
}
}
}
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 valueLen = tvb_reported_length (value_buff);
guint peek = 0;
struct timeval timeValue;
guint offsetNew = 0;
guint value = 0;
guint valueLength = 0;
char valString[100];
char valNum1[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);
#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) /* Constrained-media (short-integer) */
{
proto_tree_add_uint (tree, hf_wsp_header_accept, header_buff, offset, headerLen, (peek & 0x7F));
break;
}
if (peek >= 32) /* Constrained-media (text) */
{
proto_tree_add_string (tree, hf_wsp_header_accept_str,header_buff,offset,headerLen,
tvb_get_ptr (value_buff, 0, valueLen));
break;
}
/* general form (short length) */
offsetNew = offset+1;
valueLength = tvb_get_guint8 (value_buff, offsetNew);
if (valueLength & 0x80) /* short integer */
{
valMatch = match_strval(valueLength & 0x7f, vals_content_types);
offsetNew++;
}
else if (valueLength < 32) /* long integer */
{
if (get_long_integer(value_buff,&offsetNew,offset+peek,&value) < 0)
{
fprintf (stderr, "dissect_wsp: accept get_long_interger invalid\n");
}
valMatch = match_strval(value, vals_content_types);
offsetNew+=valueLength;
if (valMatch == NULL)
{
snprintf(valNum1,100,"Unsupported type (%d)",value);
valMatch = valNum1;
}
}
else /* text */
{
/* TODO */
}
if ((offsetNew - offset) < peek) /* Parameter */
{
value = tvb_get_guint8 (value_buff, offsetNew);
offsetNew++;
if (value & 0x80) /* well Know type */
{
switch (value & 0x7f)
{
case 0x03 :
valueLength = tvb_get_guint8 (value_buff, offsetNew);
if (valueLength & 0x80) /* short integer */
{
value = valueLength & 0x7F;
offsetNew++;
}
else if (valueLength < 32) /* Long integer */
{
if (get_long_integer(value_buff,&offsetNew,offset+peek,&value) < 0)
{
fprintf (stderr, "dissect_wsp: accept get_long_interger parameter invalid\n");
}
}
snprintf (valString, 100, "%s type %d", valMatch,value);
break;
case 0x00 :
case 0x01 :
case 0x02 :
case 0x04 :
default :
break;
}
}
}
else /* no parameter */
{
snprintf (valString, 100, "%s", valMatch);
}
/* Add string to tree */
proto_tree_add_string (tree, hf_wsp_header_accept_str,
header_buff, 0, headerLen, valString);
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_language, header_buff, offset,
headerLen, tvb_get_guint8 (value_buff, 1) );
break;
case 2:
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_language, header_buff, offset,
headerLen, tvb_get_ntohl (value_buff, 1) );
break;
default:
fprintf (stderr, "dissect_wsp: accept-language size %d NYI\n", peek);
}
}
else if (peek & 0x80)
{
proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, headerLen, (peek & 0x7F) );
}
else
{
proto_tree_add_string (tree, hf_wsp_header_accept_language_str, header_buff, offset,headerLen,
tvb_get_ptr (value_buff, 0, valueLen));
}
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)",
val_to_str (peek, vals_cache_control,
"Unknown (0x%02x)"),
(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 < 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));
}
else
{
fprintf (stderr, "dissect_wsp: Content-Length long-integer size NYI\n");
}
break;
case 0x12: /* Date */
add_date_value (value_buff, 0, tree,
hf_wsp_header_date, header_buff, offset,
headerLen, &timeValue, "Date");
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 */
add_date_value (value_buff, 0, tree,
hf_wsp_header_expires, header_buff, offset,
headerLen, &timeValue, "Expires");
break;
case 0x17: /* If-Modified-Since */
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 */
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 */
add_date_value (value_buff, 0, tree,
hf_wsp_header_last_modified, header_buff, offset,
headerLen, &timeValue, "Last-Modified");
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 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;
}
}
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)
{
peek = tvb_get_guint8 (value_buff,offset);
if (peek < 31)
{
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
{
fprintf (stderr, "dissect_wsp: X-WAP.TOD peek %X NYI\n",peek);
}
}
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));
}
}
}
static void
add_capabilities (proto_tree *tree, tvbuff_t *tvb)
{
proto_item *ti;
proto_tree *wsp_capabilities;
guint offset = 0;
guint offsetStr = 0;
guint capabilitiesLen = tvb_reported_length (tvb);
guint8 capabilitiesStart = 0;
guint peek = 0;
guint length = 0;
guint value = 0;
guint i;
char valString[200];
#ifdef DEBUG
fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, capabilitiesLen);
#endif
/* End of buffer */
if (capabilitiesLen <= 0)
{
fprintf (stderr, "dissect_wsp: Capabilities = 0\n");
return;
}
#ifdef DEBUG
fprintf (stderr, "dissect_wsp: capabilities to process\n");
#endif
ti = proto_tree_add_item (tree, hf_wsp_capabilities_section,tvb,offset,capabilitiesLen,bo_little_endian);
wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
/* Parse Headers */
while (offset < capabilitiesLen)
{
/* Loop round each header */
capabilitiesStart = offset;
length = tvb_get_guint8 (tvb, capabilitiesStart);
if (length >= 127) /* length */
{
#ifdef DEBUG
fprintf (stderr, "dissect_wsp: capabilities length invalid %d\n",length);
#endif
offset+=length;
continue;
}
offset++;
peek = tvb_get_guint8 (tvb, offset);
offset++;
switch (peek & 0x7f)
{
case 0x00 : /* Client-SDU-Size */
value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_client_SDU, tvb, capabilitiesStart, length+1, value);
break;
case 0x01 : /* Server-SDU-Size */
value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_server_SDU, tvb, capabilitiesStart, length+1, value);
break;
case 0x02 : /* Protocol Options */
value = get_uintvar (tvb, offset, length+capabilitiesStart+1);
i = 0;
valString[0]=0;
if (value & 0x80)
{
i += snprintf(valString+i,200-1,"%s","(Confirmed push facility) ");
}
if (value & 0x40)
{
i += snprintf(valString+i,200-1,"%s","(Push facility) ");
}
if (value & 0x20)
{
i += snprintf(valString+i,200-1,"%s","(Session resume facility) ");
}
if (value & 0x10)
{
i += snprintf(valString+i,200-1,"%s","(Acknowledgement headers) ");
}
proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_protocol_opt, tvb, capabilitiesStart, length+1, valString);
break;
case 0x03 : /* Method-MOR */
value = tvb_get_guint8(tvb, offset);
proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_method_MOR, tvb, capabilitiesStart, length+1, value);
break;
case 0x04 : /* Push-MOR */
value = tvb_get_guint8(tvb, offset);
proto_tree_add_uint (wsp_capabilities, hf_wsp_capabilities_push_MOR, tvb, capabilitiesStart, length+1, value);
break;
break;
case 0x05 : /* Extended Methods */
offsetStr = offset;
offset++;
i = 0;
while ((offsetStr-capabilitiesStart) <= length)
{
value = tvb_get_guint8(tvb, offsetStr);
i += snprintf(valString+i,200-i,"(%d - ",value);
offsetStr++;
for (;(valString[i] = tvb_get_guint8(tvb, offsetStr));i++,offsetStr++);
offsetStr++;
valString[i++] = ')';
valString[i++] = ' ';
}
valString[i]=0;
proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_extended_methods, tvb, capabilitiesStart, length+1, valString);
break;
case 0x06 : /* Header Code Pages */
offsetStr = offset;
offset++;
i = 0;
while ((offsetStr-capabilitiesStart) <= length)
{
value = tvb_get_guint8(tvb, offsetStr);
i += snprintf(valString+i,200-i,"(%d - ",value);
offsetStr++;
for (;(valString[i] = tvb_get_guint8(tvb, offsetStr));i++,offsetStr++);
offsetStr++;
valString[i++] = ')';
valString[i++] = ' ';
}
valString[i]=0;
proto_tree_add_string(wsp_capabilities, hf_wsp_capabilities_header_code_pages, tvb, capabilitiesStart, length+1, valString);
break;
case 0x07 : /* Aliases */
break;
default:
proto_tree_add_text (wsp_capabilities, tvb , capabilitiesStart, length+1,
"Unsupported Header (0x%02X)", peek & 0x7F);
break;
}
offset=capabilitiesStart+length+1;
}
}
static guint
get_uintvar (tvbuff_t *tvb, guint offset, guint offsetEnd)
{
guint value = 0;
guint octet;
do
{
octet = tvb_get_guint8 (tvb, offset);
offset++;
value <<= 7;
value += octet & 0x7f;
}
while ((offsetEnd > offset) && (octet & 0x80));
return value;
}
static 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);
}
static 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);
}
/* 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);
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);
}
static 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;
}
static 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;
/* VERIFY ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,tvb_length_remaining(tvb, offset),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 */
{
/* Iterate through post data */
for (offset = 0; offset < tvb_reported_length (tvb); offset++)
{
peek = tvb_get_guint8 (tvb, offset);
if (peek == '=')
{
variableEnd = offset;
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);
}
}
}
static 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);
variableBuffer[variableLength] = 0;
if (valueEnd < valueStart)
{
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", HFILL
}
},
{ &hf_wsp_header_pdu_type,
{ "PDU Type",
"wsp.pdu_type",
FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
"PDU Type", HFILL
}
},
{ &hf_wsp_version_major,
{ "Version (Major)",
"wsp.version.major",
FT_UINT8, BASE_DEC, NULL, 0xF0,
"Version (Major)", HFILL
}
},
{ &hf_wsp_version_minor,
{ "Version (Minor)",
"wsp.version.minor",
FT_UINT8, BASE_DEC, NULL, 0x0F,
"Version (Minor)", HFILL
}
},
{ &hf_wsp_capability_length,
{ "Capability Length",
"wsp.capability.length",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Capability Length", HFILL
}
},
{ &hf_wsp_header_length,
{ "Headers Length",
"wsp.headers_length",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Headers Length", HFILL
}
},
{ &hf_wsp_capabilities_section,
{ "Capabilities",
"wsp.capabilities",
FT_NONE, BASE_DEC, NULL, 0x00,
"Capabilities", HFILL
}
},
{ &hf_wsp_headers_section,
{ "Headers",
"wsp.headers",
FT_NONE, BASE_DEC, NULL, 0x00,
"Headers", HFILL
}
},
{ &hf_wsp_header,
{ "Header",
"wsp.headers.header",
FT_NONE, BASE_DEC, NULL, 0x00,
"Header", HFILL
}
},
{ &hf_wsp_header_uri_len,
{ "URI Length",
"wsp.uri_length",
FT_UINT32, BASE_DEC, NULL, 0x00,
"URI Length", HFILL
}
},
{ &hf_wsp_header_uri,
{ "URI",
"wsp.uri",
FT_STRING, BASE_NONE, NULL, 0x00,
"URI", HFILL
}
},
{ &hf_wsp_server_session_id,
{ "Server Session ID",
"wsp.server.session_id",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Server Session ID", HFILL
}
},
{ &hf_wsp_header_status,
{ "Status",
"wsp.reply.status",
FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
"Status", HFILL
}
},
{ &hf_wsp_content_type,
{ "Content Type",
"wsp.content_type.type",
FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
"Content Type", HFILL
}
},
{ &hf_wsp_parameter_well_known_charset,
{ "Charset",
"wsp.content_type.parameter.charset",
FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
"Charset", HFILL
}
},
{ &hf_wsp_reply_data,
{ "Data",
"wsp.reply.data",
FT_NONE, BASE_NONE, NULL, 0x00,
"Data", HFILL
}
},
{ &hf_wsp_header_shift_code,
{ "Shift code",
"wsp.header.shift",
/*FT_NONE, BASE_DEC, NULL, 0x00,*/
FT_UINT8, BASE_HEX, NULL, 0x00,
"Shift code", HFILL
}
},
{ &hf_wsp_header_accept,
{ "Accept",
"wsp.header.accept",
/*FT_NONE, BASE_DEC, NULL, 0x00,*/
FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
"Accept", HFILL
}
},
{ &hf_wsp_header_accept_str,
{ "Accept",
"wsp.header.accept.string",
FT_STRING, BASE_NONE, NULL, 0x00,
"Accept", HFILL
}
},
{ &hf_wsp_header_accept_charset,
{ "Accept-Charset",
"wsp.header.accept_charset",
FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
"Accept-Charset", HFILL
}
},
{ &hf_wsp_header_accept_charset_str,
{ "Accept-Charset",
"wsp.header.accept_charset.string",
FT_STRING, BASE_NONE, NULL, 0x00,
"Accept-Charset", HFILL
}
},
{ &hf_wsp_header_accept_language,
{ "Accept-Language",
"wsp.header.accept_language",
FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
"Accept-Language", HFILL
}
},
{ &hf_wsp_header_accept_language_str,
{ "Accept-Language",
"wsp.header.accept_language.string",
FT_STRING, BASE_NONE, NULL, 0x00,
"Accept-Language", HFILL
}
},
{ &hf_wsp_header_accept_ranges,
{ "Accept-Ranges",
"wsp.header.accept_ranges",
FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
"Accept-Ranges", HFILL
}
},
{ &hf_wsp_header_age,
{ "Age",
"wsp.header.age",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Age", HFILL
}
},
{ &hf_wsp_header_cache_control,
{ "Cache-Control",
"wsp.header.cache_control",
FT_UINT8, BASE_HEX, VALS ( vals_cache_control ), 0x00,
"Cache-Control", HFILL
}
},
{ &hf_wsp_header_content_length,
{ "Content-Length",
"wsp.header.content_length",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Content-Length", HFILL
}
},
{ &hf_wsp_header_date,
{ "Date",
"wsp.header.date",
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
"Date", HFILL
}
},
{ &hf_wsp_header_etag,
{ "Etag",
"wsp.header.etag",
/*FT_NONE, BASE_DEC, NULL, 0x00,*/
FT_STRING, BASE_NONE, NULL, 0x00,
"Etag", HFILL
}
},
{ &hf_wsp_header_expires,
{ "Expires",
"wsp.header.expires",
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
"Expires", HFILL
}
},
{ &hf_wsp_header_last_modified,
{ "Last-Modified",
"wsp.header.last_modified",
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
"Last-Modified", HFILL
}
},
{ &hf_wsp_header_location,
{ "Location",
"wsp.header.location",
FT_STRING, BASE_NONE, NULL, 0x00,
"Location", HFILL
}
},
{ &hf_wsp_header_if_modified_since,
{ "If-Modified-Since",
"wsp.header.if_modified_since",
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
"If-Modified-Since", HFILL
}
},
{ &hf_wsp_header_server,
{ "Server",
"wsp.header.server",
/*FT_NONE, BASE_DEC, NULL, 0x00,*/
FT_STRING, BASE_NONE, NULL, 0x00,
"Server", HFILL
}
},
{ &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", HFILL
}
},
{ &hf_wsp_header_transfer_encoding_str,
{ "Transfer Encoding",
"wsp.header.transfer_enc_str",
FT_STRING, BASE_NONE, NULL, 0x00,
"Transfer Encoding", HFILL
}
},
{ &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", HFILL
}
},
{ &hf_wsp_header_via,
{ "Via",
"wsp.header.via",
FT_STRING, BASE_NONE, NULL, 0x00,
"Via", HFILL
}
},
{ &hf_wsp_header_application_header,
{ "Application Header",
"wsp.header.application_header",
FT_STRING, BASE_NONE, NULL, 0x00,
"Application Header", HFILL
}
},
{ &hf_wsp_header_application_value,
{ "Application Header Value",
"wsp.header.application_header.value",
FT_STRING, BASE_NONE, NULL, 0x00,
"Application Header Value", HFILL
}
},
{ &hf_wsp_header_x_wap_tod,
{ "X-WAP.TOD",
"wsp.header.x_wap_tod",
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
"X-WAP.TOD", HFILL
}
},
{ &hf_wsp_capabilities_client_SDU,
{ "Client SDU",
"wsp.capabilities.client_SDU",
FT_UINT8, BASE_DEC, NULL, 0x00,
"Client SDU", HFILL
}
},
{ &hf_wsp_capabilities_server_SDU,
{ "Server SDU",
"wsp.capabilities.server_SDU",
FT_UINT8, BASE_DEC, NULL, 0x00,
"Server SDU", HFILL
}
},
{ &hf_wsp_capabilities_protocol_opt,
{ "Protocol Options",
"wsp.capabilities.protocol_opt",
FT_STRING, BASE_HEX, NULL, 0x00,
"Protocol Options", HFILL
}
},
{ &hf_wsp_capabilities_method_MOR,
{ "Method MOR",
"wsp.capabilities.method_mor",
FT_UINT8, BASE_DEC, NULL, 0x00,
"Method MOR", HFILL
}
},
{ &hf_wsp_capabilities_push_MOR,
{ "Push MOR",
"wsp.capabilities.push_mor",
FT_UINT8, BASE_DEC, NULL, 0x00,
"Push MOR", HFILL
}
},
{ &hf_wsp_capabilities_extended_methods,
{ "Extended Methods",
"wsp.capabilities.extend_methods",
FT_STRING, BASE_HEX, NULL, 0x00,
"Extended Methods", HFILL
}
},
{ &hf_wsp_capabilities_header_code_pages,
{ "Header Code Pages",
"wsp.capabilities.code_pages",
FT_STRING, BASE_HEX, NULL, 0x00,
"Header Code Pages", HFILL
}
},
{ &hf_wsp_capabilities_aliases,
{ "Aliases",
"wsp.capabilities.aliases",
FT_UINT8, BASE_HEX, NULL, 0x00,
"Aliases", HFILL
}
},
{ &hf_wsp_post_data,
{ "Post Data",
"wsp.post.data",
FT_NONE, BASE_NONE, NULL, 0x00,
"Post Data", HFILL
}
},
};
/* 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 */
"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_fromwap, 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_fromudp, proto_wsp);
/* This dissector is also called from the WTP and WTLS dissectors */
}
static gint get_long_integer (tvbuff_t *tvb, guint *offset, guint offset_end, guint *value)
{
guint valueLength;
valueLength = tvb_get_guint8(tvb,*offset);
if ((valueLength+*offset) > offset_end)
{
*value = 0;
return (-1);
}
(*offset)++;
switch (valueLength)
{
case 1:
*value = tvb_get_guint8(tvb,*offset);
break;
case 2:
*value = tvb_get_ntohs(tvb,*offset);
break;
case 3:
*value = tvb_get_ntoh24(tvb,*offset);
break;
case 4:
*value = tvb_get_ntohl(tvb,*offset);
break;
default:
/* TODO: Need to read peek octets */
*value = 0;
fprintf (stderr, "dissect_wsp: get_long_integer size %d NYI\n", valueLength);
break;
}
(*offset) += valueLength;
return 0;
}