forked from osmocom/wireshark
![Olivier Biot](/assets/img/avatar_default.png)
"media_type" dissector table defined in the HTTP dissector), allowing us to make the distinction between dissecting a standaone media type and an encapsulated media type (e.g., encapsulated in a multipart entity). Provide separate dissectors for "standalone" and "encapsulated" MMSE, hence fixing the needlessly clearing of the Info column when the MMSE is only part of the encapsulated entity (e.g., in the PAP protocol for WAP Push). svn path=/trunk/; revision=9988
1074 lines
30 KiB
C
1074 lines
30 KiB
C
/* packet-mmse.c
|
|
* Routines for MMS Message Encapsulation dissection
|
|
* Copyright 2001, Tom Uijldert <tom.uijldert@cmg.nl>
|
|
*
|
|
* $Id: packet-mmse.c,v 1.32 2004/02/06 01:07:51 obiot Exp $
|
|
*
|
|
* Ethereal - Network traffic analyzer
|
|
* By Gerald Combs <gerald@ethereal.com>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* 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.
|
|
* ----------
|
|
*
|
|
* Dissector of an encoded Multimedia message PDU, as defined by the WAPForum
|
|
* (http://www.wapforum.org) in "WAP-209-MMSEncapsulation-20020105-a".
|
|
*/
|
|
|
|
/* This file has been edited with 8-space tabs and 4-space indentation */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include <epan/packet.h>
|
|
#include "packet-wap.h"
|
|
#include "packet-wsp.h"
|
|
/* #include "packet-mmse.h" */ /* We autoregister */
|
|
|
|
#define MM_QUOTE 0x7F /* Quoted string */
|
|
|
|
#define MMS_CONTENT_TYPE 0x3E /* WINA-value for mms-message */
|
|
|
|
/* General-purpose debug logger.
|
|
* Requires double parentheses because of variable arguments of printf().
|
|
*
|
|
* Enable debug logging for MMSE by defining AM_CFLAGS
|
|
* so that it contains "-DDEBUG_mmse"
|
|
*/
|
|
#ifdef DEBUG_mmse
|
|
#define DebugLog(x) \
|
|
printf("%s:%u: ", __FILE__, __LINE__); \
|
|
printf x; \
|
|
fflush(stdout)
|
|
#else
|
|
#define DebugLog(x) ;
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Forward declarations
|
|
*/
|
|
static void dissect_mmse_standalone(tvbuff_t *, packet_info *, proto_tree *);
|
|
static void dissect_mmse_encapsulated(tvbuff_t *, packet_info *, proto_tree *);
|
|
static void dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|
guint8 pdut, char *message_type);
|
|
|
|
/*
|
|
* Header field values
|
|
*/
|
|
#define MM_BCC_HDR 0x81 /* Bcc */
|
|
#define MM_CC_HDR 0x82 /* Cc */
|
|
#define MM_CLOCATION_HDR 0x83 /* Content-Location */
|
|
#define MM_CTYPE_HDR 0x84 /* Content-Type */
|
|
#define MM_DATE_HDR 0x85 /* Date */
|
|
#define MM_DREPORT_HDR 0x86 /* Delivery-Report */
|
|
#define MM_DTIME_HDR 0x87 /* Delivery-Time */
|
|
#define MM_EXPIRY_HDR 0x88 /* Expiry */
|
|
#define MM_FROM_HDR 0x89 /* From */
|
|
#define MM_MCLASS_HDR 0x8A /* Message-Class */
|
|
#define MM_MID_HDR 0x8B /* Message-ID */
|
|
#define MM_MTYPE_HDR 0x8C /* Message-Type */
|
|
#define MM_VERSION_HDR 0x8D /* MMS-Version */
|
|
#define MM_MSIZE_HDR 0x8E /* Message-Size */
|
|
#define MM_PRIORITY_HDR 0x8F /* Priority */
|
|
#define MM_RREPLY_HDR 0x90 /* Read-Reply */
|
|
#define MM_RALLOWED_HDR 0x91 /* Report-Allowed */
|
|
#define MM_RSTATUS_HDR 0x92 /* Response-Status */
|
|
#define MM_RTEXT_HDR 0x93 /* Response-Text */
|
|
#define MM_SVISIBILITY_HDR 0x94 /* Sender-Visibility */
|
|
#define MM_STATUS_HDR 0x95 /* Status */
|
|
#define MM_SUBJECT_HDR 0x96 /* Subject */
|
|
#define MM_TO_HDR 0x97 /* To */
|
|
#define MM_TID_HDR 0x98 /* Transaction-Id */
|
|
|
|
static const value_string vals_mm_header_names[] = {
|
|
{ MM_BCC_HDR, "Bcc" },
|
|
{ MM_CC_HDR, "Cc" },
|
|
{ MM_CLOCATION_HDR, "Content-Location" },
|
|
{ MM_CTYPE_HDR, "Content-Type" },
|
|
{ MM_DATE_HDR, "Date" },
|
|
{ MM_DREPORT_HDR, "Delivery-Report" },
|
|
{ MM_DTIME_HDR, "Delivery-Time" },
|
|
{ MM_EXPIRY_HDR, "Expiry" },
|
|
{ MM_FROM_HDR, "From" },
|
|
{ MM_MCLASS_HDR, "Message-Class" },
|
|
{ MM_MID_HDR, "Message-ID" },
|
|
{ MM_MTYPE_HDR, "Message-Type" },
|
|
{ MM_VERSION_HDR, "MMS-Version" },
|
|
{ MM_MSIZE_HDR, "Message-Size" },
|
|
{ MM_PRIORITY_HDR, "Priority" },
|
|
{ MM_RREPLY_HDR, "Read-Reply" },
|
|
{ MM_RALLOWED_HDR, "Report-Allowed" },
|
|
{ MM_RSTATUS_HDR, "Response-Status" },
|
|
{ MM_RTEXT_HDR, "Response-Text" },
|
|
{ MM_SVISIBILITY_HDR, "Sender-Visibility" },
|
|
{ MM_STATUS_HDR, "Status" },
|
|
{ MM_SUBJECT_HDR, "Subject" },
|
|
{ MM_TO_HDR, "To" },
|
|
{ MM_TID_HDR, "Transaction-Id" },
|
|
|
|
{ 0x00, NULL },
|
|
};
|
|
/*
|
|
* Initialize the protocol and registered fields
|
|
*/
|
|
static int proto_mmse = -1;
|
|
|
|
static int hf_mmse_message_type = -1;
|
|
static int hf_mmse_transaction_id = -1;
|
|
static int hf_mmse_mms_version = -1;
|
|
static int hf_mmse_bcc = -1;
|
|
static int hf_mmse_cc = -1;
|
|
static int hf_mmse_content_location = -1;
|
|
static int hf_mmse_date = -1;
|
|
static int hf_mmse_delivery_report = -1;
|
|
static int hf_mmse_delivery_time_abs = -1;
|
|
static int hf_mmse_delivery_time_rel = -1;
|
|
static int hf_mmse_expiry_abs = -1;
|
|
static int hf_mmse_expiry_rel = -1;
|
|
static int hf_mmse_from = -1;
|
|
static int hf_mmse_message_class_id = -1;
|
|
static int hf_mmse_message_class_str = -1;
|
|
static int hf_mmse_message_id = -1;
|
|
static int hf_mmse_message_size = -1;
|
|
static int hf_mmse_priority = -1;
|
|
static int hf_mmse_read_reply = -1;
|
|
static int hf_mmse_report_allowed = -1;
|
|
static int hf_mmse_response_status = -1;
|
|
static int hf_mmse_response_text = -1;
|
|
static int hf_mmse_sender_visibility = -1;
|
|
static int hf_mmse_status = -1;
|
|
static int hf_mmse_subject = -1;
|
|
static int hf_mmse_to = -1;
|
|
static int hf_mmse_content_type = -1;
|
|
static int hf_mmse_ffheader = -1;
|
|
|
|
/*
|
|
* Initialize the subtree pointers
|
|
*/
|
|
static gint ett_mmse = -1;
|
|
|
|
/*
|
|
* Valuestrings for header contents
|
|
*/
|
|
|
|
#define PDU_M_SEND_REQ 0x80
|
|
#define PDU_M_SEND_CONF 0x81
|
|
#define PDU_M_NOTIFICATION_IND 0x82
|
|
#define PDU_M_NOTIFYRESP_IND 0x83
|
|
#define PDU_M_RETRIEVE_CONF 0x84
|
|
#define PDU_M_ACKNOWLEDGE_IND 0x85
|
|
#define PDU_M_DELIVERY_IND 0x86
|
|
|
|
#define pdu_has_content(pdut) \
|
|
( ((pdut) == PDU_M_SEND_REQ) \
|
|
|| ((pdut) == PDU_M_DELIVERY_IND) )
|
|
|
|
static const value_string vals_message_type[] = {
|
|
{ PDU_M_SEND_REQ, "m-send-req" },
|
|
{ PDU_M_SEND_CONF, "m-send-conf" },
|
|
{ PDU_M_NOTIFICATION_IND, "m-notification-ind" },
|
|
{ PDU_M_NOTIFYRESP_IND, "m-notifyresp-ind" },
|
|
{ PDU_M_RETRIEVE_CONF, "m-retrieve-conf" },
|
|
{ PDU_M_ACKNOWLEDGE_IND, "m-acknowledge-ind" },
|
|
{ PDU_M_DELIVERY_IND, "m-delivery-ind" },
|
|
{ 0x00, NULL },
|
|
};
|
|
|
|
static const value_string vals_yes_no[] = {
|
|
{ 0x80, "Yes" },
|
|
{ 0x81, "No" },
|
|
{ 0x00, NULL },
|
|
};
|
|
|
|
static const value_string vals_message_class[] = {
|
|
{ 0x80, "Personal" },
|
|
{ 0x81, "Advertisement" },
|
|
{ 0x82, "Informational" },
|
|
{ 0x83, "Auto" },
|
|
{ 0x00, NULL },
|
|
};
|
|
|
|
static const value_string vals_priority[] = {
|
|
{ 0x80, "Low" },
|
|
{ 0x81, "Normal" },
|
|
{ 0x82, "High" },
|
|
{ 0x00, NULL },
|
|
};
|
|
|
|
static const value_string vals_response_status[] = {
|
|
{ 0x80, "Ok" },
|
|
{ 0x81, "Unspecified" },
|
|
{ 0x82, "Service denied" },
|
|
{ 0x83, "Message format corrupt" },
|
|
{ 0x84, "Sending address unresolved" },
|
|
{ 0x85, "Message not found" },
|
|
{ 0x86, "Network problem" },
|
|
{ 0x87, "Content not accepted" },
|
|
{ 0x88, "Unsupported message" },
|
|
{ 0x00, NULL },
|
|
};
|
|
|
|
static const value_string vals_sender_visibility[] = {
|
|
{ 0x80, "Hide" },
|
|
{ 0x81, "Show" },
|
|
{ 0x00, NULL },
|
|
};
|
|
|
|
static const value_string vals_message_status[] = {
|
|
{ 0x80, "Expired" },
|
|
{ 0x81, "Retrieved" },
|
|
{ 0x82, "Rejected" },
|
|
{ 0x83, "Deferred" },
|
|
{ 0x84, "Unrecognized" },
|
|
{ 0x00, NULL },
|
|
};
|
|
|
|
/*!
|
|
* Decodes a Text-string from the protocol data
|
|
* Text-string = [Quote] *TEXT End-of-string
|
|
* Quote = <Octet 127>
|
|
* End-of-string = <Octet 0>
|
|
*
|
|
* \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
|
|
*
|
|
* \param tvb The buffer with PDU-data
|
|
* \param offset Offset within that buffer
|
|
* \param strval Pointer to variable into which to put pointer to
|
|
* buffer allocated to hold the text; must be freed
|
|
* when no longer used
|
|
*
|
|
* \return The length in bytes of the entire field
|
|
*/
|
|
static guint
|
|
get_text_string(tvbuff_t *tvb, guint offset, char **strval)
|
|
{
|
|
guint len;
|
|
|
|
DebugLog(("get_text_string(tvb = %p, offset = %u, **strval) - start\n",
|
|
vb, offset));
|
|
len = tvb_strsize(tvb, offset);
|
|
DebugLog((" [1] tvb_strsize(tvb, offset) == %u\n", len));
|
|
if (tvb_get_guint8(tvb, offset) == MM_QUOTE)
|
|
*strval = (char *)tvb_memdup(tvb, offset + 1, len - 1);
|
|
else
|
|
*strval = (char *)tvb_memdup(tvb, offset, len);
|
|
DebugLog((" [3] Return(len) == %u\n", len));
|
|
return len;
|
|
}
|
|
|
|
/*!
|
|
* Decodes a Value-length from the protocol data.
|
|
* Value-length = Short-length | (Length-quote Length)
|
|
* Short-length = <Any octet 0-30>
|
|
* Length-quote = <Octet 31>
|
|
* Length = Uintvar-integer
|
|
*
|
|
* \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
|
|
*
|
|
* \param tvb The buffer with PDU-data
|
|
* \param offset Offset within that buffer
|
|
* \param byte_count Returns the length in bytes of
|
|
* the "Value-length" field.
|
|
*
|
|
* \return The actual value of "Value-length"
|
|
*/
|
|
static guint
|
|
get_value_length(tvbuff_t *tvb, guint offset, guint *byte_count)
|
|
{
|
|
guint field;
|
|
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (field < 31)
|
|
*byte_count = 1;
|
|
else { /* Must be 31 so, Uintvar follows */
|
|
field = tvb_get_guintvar(tvb, offset, byte_count);
|
|
(*byte_count)++;
|
|
}
|
|
return field;
|
|
}
|
|
|
|
/*!
|
|
* Decodes an Encoded-string-value from the protocol data
|
|
* Encoded-string-value = Text-string | Value-length Char-set Text-string
|
|
*
|
|
* \param tvb The buffer with PDU-data
|
|
* \param offset Offset within that buffer
|
|
* \param strval Pointer to variable into which to put pointer to
|
|
* buffer allocated to hold the text; must be freed
|
|
* when no longer used
|
|
*
|
|
* \return The length in bytes of the entire field
|
|
*/
|
|
static guint
|
|
get_encoded_strval(tvbuff_t *tvb, guint offset, char **strval)
|
|
{
|
|
guint field;
|
|
guint length;
|
|
guint count;
|
|
|
|
field = tvb_get_guint8(tvb, offset);
|
|
|
|
if (field < 32) {
|
|
length = get_value_length(tvb, offset, &count);
|
|
/* \todo Something with "Char-set", skip for now */
|
|
*strval = (char *)tvb_get_string(tvb, offset + count + 1, length - 1);
|
|
return count + length;
|
|
} else
|
|
return get_text_string(tvb, offset, strval);
|
|
}
|
|
|
|
/*!
|
|
* Decodes a Long-integer from the protocol data
|
|
* Long-integer = Short-length Multi-octet-integer
|
|
* Short-length = <Any octet 0-30>
|
|
* Multi-octet-integer = 1*30OCTET
|
|
*
|
|
* \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
|
|
*
|
|
* \param tvb The buffer with PDU-data
|
|
* \param offset Offset within that buffer
|
|
* \param byte_count Returns the length in bytes of the field
|
|
*
|
|
* \return The value of the Long-integer
|
|
*
|
|
* \note A maximum of 4-byte integers will be handled.
|
|
*/
|
|
static guint
|
|
get_long_integer(tvbuff_t *tvb, guint offset, guint *byte_count)
|
|
{
|
|
guint val;
|
|
|
|
*byte_count = tvb_get_guint8(tvb, offset++);
|
|
switch (*byte_count) {
|
|
case 1:
|
|
val = tvb_get_guint8(tvb, offset);
|
|
break;
|
|
case 2:
|
|
val = tvb_get_ntohs(tvb, offset);
|
|
break;
|
|
case 3:
|
|
val = tvb_get_ntoh24(tvb, offset);
|
|
break;
|
|
case 4:
|
|
val = tvb_get_ntohl(tvb, offset);
|
|
break;
|
|
default:
|
|
val = 0;
|
|
break;
|
|
}
|
|
(*byte_count)++;
|
|
return val;
|
|
}
|
|
|
|
/* Code to actually dissect the packets */
|
|
static gboolean
|
|
dissect_mmse_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
{
|
|
guint8 pdut;
|
|
|
|
DebugLog(("dissect_mmse_heur()\n"));
|
|
/*
|
|
* Check if data makes sense for it to be dissected as MMSE: Message-type
|
|
* field must make sense and followed by either Transaction-Id
|
|
* or MMS-Version header
|
|
*/
|
|
if (tvb_get_guint8(tvb, 0) != MM_MTYPE_HDR)
|
|
return FALSE;
|
|
pdut = tvb_get_guint8(tvb, 1);
|
|
if (match_strval(pdut, vals_message_type) == NULL)
|
|
return FALSE;
|
|
if ((tvb_get_guint8(tvb, 2) != MM_TID_HDR) &&
|
|
(tvb_get_guint8(tvb, 2) != MM_VERSION_HDR))
|
|
return FALSE;
|
|
dissect_mmse_standalone(tvb, pinfo, tree);
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
dissect_mmse_standalone(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
{
|
|
guint8 pdut;
|
|
char *message_type;
|
|
|
|
DebugLog(("dissect_mmse_standalone() - START (Packet %u)\n",
|
|
pinfo->fd->num));
|
|
|
|
pdut = tvb_get_guint8(tvb, 1);
|
|
message_type = match_strval(pdut, vals_message_type);
|
|
|
|
/* Make entries in Protocol column and Info column on summary display */
|
|
if (check_col(pinfo->cinfo, COL_PROTOCOL))
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "MMSE");
|
|
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "MMS %s", message_type);
|
|
}
|
|
|
|
dissect_mmse(tvb, pinfo, tree, pdut, message_type);
|
|
}
|
|
|
|
static void
|
|
dissect_mmse_encapsulated(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
{
|
|
guint8 pdut;
|
|
char *message_type;
|
|
|
|
DebugLog(("dissect_mmse_encapsulated() - START (Packet %u)\n",
|
|
pinfo->fd->num));
|
|
|
|
pdut = tvb_get_guint8(tvb, 1);
|
|
message_type = match_strval(pdut, vals_message_type);
|
|
|
|
/* Make entries in Info column on summary display */
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(MMS %s)",
|
|
message_type);
|
|
}
|
|
|
|
dissect_mmse(tvb, pinfo, tree, pdut, message_type);
|
|
}
|
|
|
|
static void
|
|
dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 pdut,
|
|
char *message_type)
|
|
{
|
|
guint offset;
|
|
guint8 field = 0;
|
|
char *strval;
|
|
guint length;
|
|
guint count;
|
|
|
|
/* Set up structures needed to add the protocol subtree and manage it */
|
|
proto_item *ti = NULL;
|
|
proto_tree *mmse_tree = NULL;
|
|
|
|
DebugLog(("dissect_mmse() - START (Packet %u)\n", pinfo->fd->num));
|
|
|
|
/* If tree == NULL then we are only interested in protocol dissection
|
|
* up to reassembly and handoff to subdissectors if applicable; the
|
|
* columns must be set appropriately too.
|
|
* If tree != NULL then we also want to display the protocol tree
|
|
* with its fields.
|
|
*
|
|
* In the interest of speed, skip protocol tree item generation
|
|
* if tree is NULL.
|
|
*/
|
|
if (tree) {
|
|
DebugLog(("tree != NULL\n"));
|
|
|
|
ti = proto_tree_add_item(tree, proto_mmse, tvb, 0, -1, FALSE);
|
|
proto_item_append_text(ti, ", Type: %s", message_type);
|
|
/* create display subtree for the protocol */
|
|
mmse_tree = proto_item_add_subtree(ti, ett_mmse);
|
|
|
|
/* Report PDU-type */
|
|
proto_tree_add_uint(mmse_tree, hf_mmse_message_type, tvb, 0, 2, pdut);
|
|
}
|
|
|
|
offset = 2; /* Skip Message-Type */
|
|
|
|
/*
|
|
* Cycle through MMS-headers
|
|
*
|
|
* NOTE - some PDUs may convey content which can be handed off
|
|
* to subdissectors.
|
|
*/
|
|
if (tree || pdu_has_content(pdut)) {
|
|
while ((offset < tvb_reported_length(tvb)) &&
|
|
(field = tvb_get_guint8(tvb, offset++)) != MM_CTYPE_HDR)
|
|
{
|
|
DebugLog(("\tField = 0x%02X (offset = %u): %s\n",
|
|
field, offset,
|
|
val_to_str(field, vals_mm_header_names,
|
|
"Unknown MMS header 0x%02X")));
|
|
switch (field)
|
|
{
|
|
case MM_TID_HDR: /* Text-string */
|
|
length = get_text_string(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree, hf_mmse_transaction_id,
|
|
tvb, offset - 1, length + 1,strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
break;
|
|
case MM_VERSION_HDR: /* nibble-Major/nibble-minor*/
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (tree) {
|
|
guint8 major, minor;
|
|
|
|
major = (field & 0x70) >> 4;
|
|
minor = field & 0x0F;
|
|
if (minor == 0x0F)
|
|
strval = g_strdup_printf("%u", major);
|
|
else
|
|
strval = g_strdup_printf("%u.%u", major, minor);
|
|
proto_tree_add_string(mmse_tree, hf_mmse_mms_version,
|
|
tvb, offset - 2, 2, strval);
|
|
g_free(strval);
|
|
}
|
|
break;
|
|
case MM_BCC_HDR: /* Encoded-string-value */
|
|
length = get_encoded_strval(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree, hf_mmse_bcc, tvb,
|
|
offset - 1, length + 1, strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
break;
|
|
case MM_CC_HDR: /* Encoded-string-value */
|
|
length = get_encoded_strval(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree, hf_mmse_cc, tvb,
|
|
offset - 1, length + 1, strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
break;
|
|
case MM_CLOCATION_HDR: /* Uri-value */
|
|
length = get_text_string(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree,
|
|
hf_mmse_content_location,
|
|
tvb, offset - 1, length + 1,strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
break;
|
|
case MM_DATE_HDR: /* Long-integer */
|
|
{
|
|
guint tval;
|
|
nstime_t tmptime;
|
|
|
|
tval = get_long_integer(tvb, offset, &count);
|
|
tmptime.secs = tval;
|
|
tmptime.nsecs = 0;
|
|
if (tree) {
|
|
proto_tree_add_time(mmse_tree, hf_mmse_date, tvb,
|
|
offset - 1, count + 1, &tmptime);
|
|
}
|
|
}
|
|
offset += count;
|
|
break;
|
|
case MM_DREPORT_HDR: /* Yes|No */
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree,
|
|
hf_mmse_delivery_report,
|
|
tvb, offset - 2, 2, field);
|
|
}
|
|
break;
|
|
case MM_DTIME_HDR:
|
|
/*
|
|
* Value-length(Absolute-token Date-value|
|
|
* Relative-token Delta-seconds-value)
|
|
*/
|
|
length = get_value_length(tvb, offset, &count);
|
|
field = tvb_get_guint8(tvb, offset + count);
|
|
if (tree) {
|
|
guint tval;
|
|
nstime_t tmptime;
|
|
guint cnt;
|
|
|
|
tval = get_long_integer(tvb, offset + count + 1, &cnt);
|
|
tmptime.secs = tval;
|
|
tmptime.nsecs = 0;
|
|
|
|
if (field == 0x80)
|
|
proto_tree_add_time(mmse_tree,
|
|
hf_mmse_delivery_time_abs,
|
|
tvb, offset - 1,
|
|
length + count + 1, &tmptime);
|
|
else
|
|
proto_tree_add_time(mmse_tree,
|
|
hf_mmse_delivery_time_rel,
|
|
tvb, offset - 1,
|
|
length + count + 1, &tmptime);
|
|
}
|
|
offset += length + count;
|
|
break;
|
|
case MM_EXPIRY_HDR:
|
|
/*
|
|
* Value-length(Absolute-token Date-value|
|
|
* Relative-token Delta-seconds-value)
|
|
*/
|
|
length = get_value_length(tvb, offset, &count);
|
|
field = tvb_get_guint8(tvb, offset + count);
|
|
if (tree) {
|
|
guint tval;
|
|
nstime_t tmptime;
|
|
guint cnt;
|
|
|
|
tval = get_long_integer(tvb, offset + count + 1, &cnt);
|
|
tmptime.secs = tval;
|
|
tmptime.nsecs = 0;
|
|
|
|
if (field == 0x80)
|
|
proto_tree_add_time(mmse_tree, hf_mmse_expiry_abs,
|
|
tvb, offset - 1,
|
|
length + count + 1, &tmptime);
|
|
else
|
|
proto_tree_add_time(mmse_tree, hf_mmse_expiry_rel,
|
|
tvb, offset - 1,
|
|
length + count + 1, &tmptime);
|
|
}
|
|
offset += length + count;
|
|
break;
|
|
case MM_FROM_HDR:
|
|
/*
|
|
* Value-length(Address-present-token Encoded-string-value
|
|
* |Insert-address-token)
|
|
*/
|
|
length = get_value_length(tvb, offset, &count);
|
|
if (tree) {
|
|
field = tvb_get_guint8(tvb, offset + count);
|
|
if (field == 0x81) {
|
|
proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
|
|
offset-1, length + count + 1,
|
|
"<insert address>");
|
|
} else {
|
|
(void) get_encoded_strval(tvb, offset + count + 1,
|
|
&strval);
|
|
proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
|
|
offset-1, length + count + 1, strval);
|
|
g_free(strval);
|
|
}
|
|
}
|
|
offset += length + count;
|
|
break;
|
|
case MM_MCLASS_HDR:
|
|
/*
|
|
* Class-identifier|Text-string
|
|
*/
|
|
field = tvb_get_guint8(tvb, offset);
|
|
if (field & 0x80) {
|
|
offset++;
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree,
|
|
hf_mmse_message_class_id,
|
|
tvb, offset - 2, 2, field);
|
|
}
|
|
} else {
|
|
length = get_text_string(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree,
|
|
hf_mmse_message_class_str,
|
|
tvb, offset - 1, length + 1,
|
|
strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
}
|
|
break;
|
|
case MM_MID_HDR: /* Text-string */
|
|
length = get_text_string(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree, hf_mmse_message_id,
|
|
tvb, offset - 1, length + 1, strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
break;
|
|
case MM_MSIZE_HDR: /* Long-integer */
|
|
length = get_long_integer(tvb, offset, &count);
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree, hf_mmse_message_size,
|
|
tvb, offset - 1, count + 1, length);
|
|
}
|
|
offset += count;
|
|
break;
|
|
case MM_PRIORITY_HDR: /* Low|Normal|High */
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree, hf_mmse_priority, tvb,
|
|
offset - 2, 2, field);
|
|
}
|
|
break;
|
|
case MM_RREPLY_HDR: /* Yes|No */
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree, hf_mmse_read_reply, tvb,
|
|
offset - 2, 2, field);
|
|
}
|
|
break;
|
|
case MM_RALLOWED_HDR: /* Yes|No */
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree, hf_mmse_report_allowed,
|
|
tvb, offset - 2, 2, field);
|
|
}
|
|
break;
|
|
case MM_RSTATUS_HDR:
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree, hf_mmse_response_status,
|
|
tvb, offset - 2, 2, field);
|
|
}
|
|
break;
|
|
case MM_RTEXT_HDR: /* Encoded-string-value */
|
|
length = get_encoded_strval(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree, hf_mmse_response_text,
|
|
tvb, offset - 1, length + 1, strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
break;
|
|
case MM_SVISIBILITY_HDR: /* Hide|Show */
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree,hf_mmse_sender_visibility,
|
|
tvb, offset - 2, 2, field);
|
|
}
|
|
break;
|
|
case MM_STATUS_HDR:
|
|
field = tvb_get_guint8(tvb, offset++);
|
|
if (tree) {
|
|
proto_tree_add_uint(mmse_tree, hf_mmse_status, tvb,
|
|
offset - 2, 2, field);
|
|
}
|
|
break;
|
|
case MM_SUBJECT_HDR: /* Encoded-string-value */
|
|
length = get_encoded_strval(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree, hf_mmse_subject, tvb,
|
|
offset - 1, length + 1, strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
break;
|
|
case MM_TO_HDR: /* Encoded-string-value */
|
|
length = get_encoded_strval(tvb, offset, &strval);
|
|
if (tree) {
|
|
proto_tree_add_string(mmse_tree, hf_mmse_to, tvb,
|
|
offset - 1, length + 1, strval);
|
|
}
|
|
g_free(strval);
|
|
offset += length;
|
|
break;
|
|
default:
|
|
if (field & 0x80) {
|
|
if (tree) {
|
|
proto_tree_add_text(mmse_tree, tvb, offset - 1, 1,
|
|
"Unknown field (0x%02x)", field);
|
|
}
|
|
} else {
|
|
guint length2;
|
|
char *strval2;
|
|
|
|
--offset;
|
|
length = get_text_string(tvb, offset, &strval);
|
|
CLEANUP_PUSH(g_free, strval);
|
|
length2= get_text_string(tvb, offset+length, &strval2);
|
|
|
|
if (tree) {
|
|
proto_tree_add_string_format(mmse_tree,
|
|
hf_mmse_ffheader, tvb, offset,
|
|
length + length2,
|
|
(const char *) tvb_get_ptr(
|
|
tvb, offset, length + length2),
|
|
"%s: %s",strval,strval2);
|
|
}
|
|
g_free(strval2);
|
|
offset += length + length2;
|
|
CLEANUP_CALL_AND_POP;
|
|
}
|
|
break;
|
|
}
|
|
DebugLog(("\tEnd(case)\n"));
|
|
}
|
|
DebugLog(("\tEnd(switch)\n"));
|
|
if (field == MM_CTYPE_HDR) {
|
|
/*
|
|
* Eeehh, we're now actually back to good old WSP content-type
|
|
* encoding. Let's steal that from the WSP-dissector.
|
|
*/
|
|
tvbuff_t *tmp_tvb;
|
|
guint type;
|
|
const char *type_str;
|
|
|
|
DebugLog(("Content-Type: [from WSP dissector]\n"));
|
|
DebugLog(("Calling add_content_type() in WSP dissector\n"));
|
|
offset = add_content_type(mmse_tree, tvb, offset, &type, &type_str);
|
|
DebugLog(("Generating new TVB subset (offset = %u)\n", offset));
|
|
tmp_tvb = tvb_new_subset(tvb, offset, -1, -1);
|
|
DebugLog(("Add POST data\n"));
|
|
add_post_data(mmse_tree, tmp_tvb, type, type_str, pinfo);
|
|
DebugLog(("Done!\n"));
|
|
}
|
|
} else {
|
|
DebugLog(("tree == NULL and PDU has no potential content\n"));
|
|
}
|
|
|
|
/* If this protocol has a sub-dissector call it here, see section 1.8 */
|
|
DebugLog(("dissect_mmse() - END\n"));
|
|
}
|
|
|
|
|
|
/* Register the protocol with Ethereal */
|
|
|
|
/* this format is required because a script is used to build the C function
|
|
* that calls all the protocol registration.
|
|
*/
|
|
void
|
|
proto_register_mmse(void)
|
|
{
|
|
/* Setup list of header fields See Section 1.6.1 for details */
|
|
static hf_register_info hf[] = {
|
|
{ &hf_mmse_message_type,
|
|
{ "Message-Type", "mmse.message_type",
|
|
FT_UINT8, BASE_HEX, VALS(vals_message_type), 0x00,
|
|
"Specifies the transaction type. Effectively defines PDU.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_transaction_id,
|
|
{ "Transaction-ID", "mmse.transaction_id",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"A unique identifier for this transaction. "
|
|
"Identifies request and corresponding response only.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_mms_version,
|
|
{ "MMS-Version", "mmse.mms_version",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Version of the protocol used.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_bcc,
|
|
{ "Bcc", "mmse.bcc",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Blind carbon copy.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_cc,
|
|
{ "Cc", "mmse.cc",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Carbon copy.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_content_location,
|
|
{ "Content-Location", "mmse.content_location",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Defines the location of the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_date,
|
|
{ "Date", "mmse.date",
|
|
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
|
|
"Arrival timestamp of the message or sending timestamp.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_delivery_report,
|
|
{ "Delivery-Report", "mmse.delivery_report",
|
|
FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
|
|
"Whether a report of message delivery is wanted or not.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_delivery_time_abs,
|
|
{ "Delivery-Time", "mmse.delivery_time.abs",
|
|
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
|
|
"The time at which message delivery is desired.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_delivery_time_rel,
|
|
{ "Delivery-Time", "mmse.delivery_time.rel",
|
|
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
|
|
"The desired message delivery delay.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_expiry_abs,
|
|
{ "Expiry", "mmse.expiry.abs",
|
|
FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
|
|
"Time when message expires and need not be delivered anymore.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_expiry_rel,
|
|
{ "Expiry", "mmse.expiry.rel",
|
|
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
|
|
"Delay before message expires and need not be delivered anymore.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_from,
|
|
{ "From", "mmse.from",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Address of the message sender.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_message_class_id,
|
|
{ "Message-Class", "mmse.message_class.id",
|
|
FT_UINT8, BASE_HEX, VALS(vals_message_class), 0x00,
|
|
"Of what category is the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_message_class_str,
|
|
{ "Message-Class", "mmse.message_class.str",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Of what category is the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_message_id,
|
|
{ "Message-Id", "mmse.message_id",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Unique identification of the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_message_size,
|
|
{ "Message-Size", "mmse.message_size",
|
|
FT_UINT32, BASE_DEC, NULL, 0x00,
|
|
"The size of the message in octets.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_priority,
|
|
{ "Priority", "mmse.priority",
|
|
FT_UINT8, BASE_HEX, VALS(vals_priority), 0x00,
|
|
"Priority of the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_read_reply,
|
|
{ "Read-Reply", "mmse.read_reply",
|
|
FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
|
|
"Whether a read report from every recipient is wanted.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_report_allowed,
|
|
{ "Report-Allowed", "mmse.report_allowed",
|
|
FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
|
|
"Sending of delivery report allowed or not.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_response_status,
|
|
{ "Response-Status", "mmse.response_status",
|
|
FT_UINT8, BASE_HEX, VALS(vals_response_status), 0x00,
|
|
"MMS-specific result of a message submission or retrieval.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_response_text,
|
|
{ "Response-Text", "mmse.response_text",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Additional information on MMS-specific result.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_sender_visibility,
|
|
{ "Sender-Visibility", "mmse.sender_visibility",
|
|
FT_UINT8, BASE_HEX, VALS(vals_sender_visibility), 0x00,
|
|
"Disclose sender identity to receiver or not.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_status,
|
|
{ "Status", "mmse.status",
|
|
FT_UINT8, BASE_HEX, VALS(vals_message_status), 0x00,
|
|
"Current status of the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_subject,
|
|
{ "Subject", "mmse.subject",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Subject of the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_to,
|
|
{ "To", "mmse.to",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Recipient(s) of the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_content_type,
|
|
{ "Data", "mmse.content_type",
|
|
FT_NONE, BASE_NONE, NULL, 0x00,
|
|
"Media content of the message.",
|
|
HFILL
|
|
}
|
|
},
|
|
{ &hf_mmse_ffheader,
|
|
{ "Free format (not encoded) header", "mmse.ffheader",
|
|
FT_STRING, BASE_NONE, NULL, 0x00,
|
|
"Application header without corresponding encoding.",
|
|
HFILL
|
|
}
|
|
},
|
|
};
|
|
/* Setup protocol subtree array */
|
|
static gint *ett[] = {
|
|
&ett_mmse,
|
|
};
|
|
|
|
/* Register the protocol name and description */
|
|
proto_mmse = proto_register_protocol("MMS Message Encapsulation",
|
|
"MMSE", "mmse");
|
|
|
|
/* Required function calls to register header fields and subtrees used */
|
|
proto_register_field_array(proto_mmse, hf, array_length(hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
}
|
|
|
|
/* If this dissector uses sub-dissector registration add registration routine.
|
|
* This format is required because a script is used to find these routines and
|
|
* create the code that calls these routines.
|
|
*/
|
|
void
|
|
proto_reg_handoff_mmse(void)
|
|
{
|
|
dissector_handle_t mmse_standalone_handle;
|
|
dissector_handle_t mmse_encapsulated_handle;
|
|
|
|
heur_dissector_add("wsp", dissect_mmse_heur, proto_mmse);
|
|
mmse_standalone_handle = create_dissector_handle(
|
|
dissect_mmse_standalone, proto_mmse);
|
|
mmse_encapsulated_handle = create_dissector_handle(
|
|
dissect_mmse_encapsulated, proto_mmse);
|
|
/* As the media types for WSP and HTTP are the same, the WSP dissector
|
|
* uses the same string dissector table as the HTTP protocol. */
|
|
dissector_add_string("media_type",
|
|
"application/vnd.wap.mms-message", mmse_standalone_handle);
|
|
dissector_add_string("multipart_media_type",
|
|
"application/vnd.wap.mms-message", mmse_encapsulated_handle);
|
|
}
|