/* packet-wtp.c
*
* Routines to dissect WTP component of WAP traffic.
- *
- * $Id: packet-wtp.c,v 1.38 2002/08/09 09:12:51 guy Exp $
+ *
+ * $Id: packet-wtp.c,v 1.55 2003/12/21 05:51:34 jmayer Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* 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.
#include "packet-wtp.h"
#include "packet-wsp.h"
-static const true_false_string continue_truth = {
+static const true_false_string continue_truth = {
"TPI Present" ,
"No TPI"
};
-static const true_false_string RID_truth = {
+static const true_false_string RID_truth = {
"Re-Transmission",
"First transmission"
};
-static const true_false_string TIDNew_truth = {
+static const true_false_string TIDNew_truth = {
"TID is new" ,
"TID is valid"
};
-static const true_false_string tid_response_truth = {
+static const true_false_string tid_response_truth = {
"Response" ,
"Original"
};
-static const true_false_string UP_truth = {
+static const true_false_string UP_truth = {
"User Acknowledgement required" ,
"User Acknowledgement optional"
};
/* Initialize the subtree pointers */
static gint ett_wtp = ETT_EMPTY;
+static gint ett_wtp_sub_pdu_tree = ETT_EMPTY;
static gint ett_header = ETT_EMPTY;
static gint ett_tpilist = ETT_EMPTY;
static gint ett_wsp_fragments = ETT_EMPTY;
static gint ett_wtp_fragment = ETT_EMPTY;
-fragment_items wtp_frag_items = {
+static const fragment_items wtp_frag_items = {
&ett_wtp_fragment,
&ett_wsp_fragments,
&hf_wtp_fragments,
&hf_wtp_fragment_multiple_tails,
&hf_wtp_fragment_too_long_fragment,
&hf_wtp_fragment_error,
+ NULL,
"fragments"
};
static void
dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- char szInfo[50];
+ static GString *szInfo = NULL;
int offCur = 0; /* current offset from start of WTP data */
unsigned char b0;
/* Set up structures we'll need to add the protocol subtree and manage it */
proto_item *ti;
proto_tree *wtp_tree = NULL;
-
+
char pdut;
char clsTransaction = ' ';
- int cchInfo;
int numMissing = 0; /* Number of missing packets in a negative ack */
int i;
tvbuff_t *wsp_tvb = NULL;
guint8 psn = 0; /* Packet sequence number*/
guint16 TID = 0; /* Transaction-Id */
+ if (szInfo == NULL)
+ szInfo = g_string_sized_new(32);
+
b0 = tvb_get_guint8 (tvb, offCur + 0);
/* Discover Concatenated PDUs */
if (b0 == 0) {
if (tree) {
ti = proto_tree_add_item(tree, proto_wtp,
tvb, offCur, 1, bo_little_endian);
- wtp_tree = proto_item_add_subtree(ti, ett_wtp);
+ wtp_tree = proto_item_add_subtree(ti, ett_wtp_sub_pdu_tree);
}
offCur = 1;
i = 1;
c_pdulen = b0;
}
if (tree) {
- proto_tree_add_item(wtp_tree, hf_wtp_header_sub_pdu_size,
- tvb, offCur, c_fieldlen, bo_big_endian);
+ proto_tree_add_uint(wtp_tree, hf_wtp_header_sub_pdu_size,
+ tvb, offCur, c_fieldlen, c_pdulen);
}
if (i > 1 && check_col(pinfo->cinfo, COL_INFO)) {
col_append_str(pinfo->cinfo, COL_INFO, ", ");
}
- wsp_tvb = tvb_new_subset(tvb, offCur + c_fieldlen, -1, c_pdulen);
+ wsp_tvb = tvb_new_subset(tvb, offCur + c_fieldlen, c_pdulen, c_pdulen);
dissect_wtp_common(wsp_tvb, pinfo, wtp_tree);
offCur += c_fieldlen + c_pdulen;
i++;
pdut = pdu_type(b0);
/* Develop the string to put in the Info column */
- cchInfo = snprintf(szInfo, sizeof( szInfo ), "WTP %s",
+ g_string_sprintf(szInfo, "WTP %s",
val_to_str(pdut, vals_pdu_type, "Unknown PDU type 0x%x"));
switch (pdut) {
TID = tvb_get_ntohs(tvb, offCur + 1);
psn = 0;
clsTransaction = transaction_class(tvb_get_guint8(tvb, offCur + 3));
- snprintf(szInfo + cchInfo, sizeof(szInfo) - cchInfo,
- " Class %d", clsTransaction);
+ g_string_sprintfa(szInfo, " Class %d", clsTransaction);
cbHeader = 4;
break;
break;
};
if (fRID) {
- strcat( szInfo, " R" );
+ g_string_append( szInfo, " R" );
};
if (fCon) { /* Scan variable part (TPI's), */
/* determine length of it */
}
#ifdef DEBUG
- fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );
+ fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );
#endif
/* Only update "Info" column when no data in this PDU will
* be handed off to a subsequent dissector.
*/
if (check_col(pinfo->cinfo, COL_INFO) &&
- ((tvb_length_remaining(tvb, offCur + cbHeader + vHeader) <= 0) ||
+ ((tvb_length_remaining(tvb, offCur + cbHeader + vHeader) <= 0) ||
(pdut == ACK) || (pdut==NEGATIVE_ACK) || (pdut==ABORT)) ) {
#ifdef DEBUG
- fprintf(stderr, "dissect_wtp: (6) About to set info_col header to %s\n", szInfo);
+ fprintf(stderr, "dissect_wtp: (6) About to set info_col header to %s\n", szInfo->str);
#endif
- col_append_str(pinfo->cinfo, COL_INFO, szInfo);
+ col_append_str(pinfo->cinfo, COL_INFO, szInfo->str);
};
/* In the interest of speed, if "tree" is NULL, don't do any work not
necessary to generate protocol tree items. */
/* Code to process the packet goes here */
#ifdef DEBUG
- fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader);
- fprintf(stderr, "dissect_wtp: offCur = %d\n", offCur);
+ fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader);
+ fprintf(stderr, "dissect_wtp: offCur = %d\n", offCur);
#endif
/* Add common items: only CON and PDU Type */
proto_tree_add_item(
wtp_tree, /* tree */
hf_wtp_header_flag_continue, /* id */
- tvb,
+ tvb,
offCur, /* start of highlight */
1, /* length of highlight*/
b0 /* value */
/* Iterate through missing packets */
for (i = 0; i < numMissing; i++)
{
- proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number, tvb, offCur + i, 1, bo_little_endian);
+ proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number, tvb, offCur + 4 + i, 1, bo_little_endian);
}
break;
unsigned char tByte;
unsigned char tpiLen;
tvbuff_t *tmp_tvb;
-
+
vHeader = 0; /* Start scan all over */
do {
} /* End of variable part of header */
} else {
#ifdef DEBUG
- fprintf(stderr, "dissect_wtp: (4) tree was %p\n", tree);
+ fprintf(stderr, "dissect_wtp: (4) tree was %p\n", tree);
#endif
}
/*
* Any remaining data ought to be WSP data (if not WTP ACK, NACK
- * or ABORT pdu), so hand off (defragmented) to the WSP dissector
+ * or ABORT pdu), so hand off (defragmented) to the WSP dissector.
+ * Note that the last packet of a fragmented WTP message needn't
+ * contain any data, so we allow payloadless packets to be
+ * reassembled. (XXX - does the reassembly code handle this
+ * for packets other than the last packet?)
*/
- if ((tvb_length_remaining(tvb, offCur + cbHeader + vHeader) > 0) &&
+ if ((tvb_reported_length_remaining(tvb, offCur + cbHeader + vHeader) >= 0) &&
! ((pdut==ACK) || (pdut==NEGATIVE_ACK) || (pdut==ABORT)))
{
int dataOffset = offCur + cbHeader + vHeader;
- guint32 dataLen = tvb_length_remaining(tvb, offCur + cbHeader + vHeader);
+ gint dataLen = tvb_reported_length_remaining(tvb, dataOffset);
gboolean save_fragmented;
- if ((pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT) ||
- (((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR)))
+ if (((pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT) ||
+ (((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR))) &&
+ tvb_bytes_exist(tvb, dataOffset, dataLen))
{ /* 1st part of segment */
save_fragmented = pinfo->fragmented;
pinfo->fragmented = TRUE;
wtp_fragment_table, psn, dataLen, !fTTR);
if (fd_head != NULL) /* Reassembled */
{
+ /* Reassembly is complete; show the reassembled PDU */
wsp_tvb = tvb_new_real_data(fd_head->data,
fd_head->len,
fd_head->len);
}
else
{
+ /* Reassembly isn't complete; just show the fragment */
if (check_col(pinfo->cinfo, COL_INFO)) /* Won't call WSP so display */
- col_append_str(pinfo->cinfo, COL_INFO, szInfo);
+ col_append_str(pinfo->cinfo, COL_INFO, szInfo->str);
+ if (tree != NULL)
+ proto_tree_add_text(wtp_tree, tvb, dataOffset, -1, "Payload");
}
pinfo->fragmented = save_fragmented;
}
- else /* Normal packet, call next dissector */
+ else
{
- wsp_tvb = tvb_new_subset(tvb, dataOffset, -1, dataLen);
- call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
+ /*
+ * Normal packet, or not all the fragment data is available;
+ * call next dissector, unless this is a segment of a
+ * segmented invoke or result and isn't the first segment.
+ */
+ if ((pdut == SEGMENTED_INVOKE || pdut == SEGMENTED_RESULT) &&
+ psn != 0) {
+ /*
+ * This is a segmented invoke or result, and not the first
+ * segment; just show it as a segmented invoke or result,
+ * don't try to dissect its payload.
+ */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "WTP %s (%u)",
+ (pdut == SEGMENTED_INVOKE ?
+ "Segmented Invoke" : "Segmented Result"),
+ psn);
+ if (tree != NULL)
+ proto_tree_add_text(wtp_tree, tvb, dataOffset, -1, "Payload");
+ } else {
+ wsp_tvb = tvb_new_subset(tvb, dataOffset, -1, -1);
+ call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
+ }
}
}
}
* XXX - can this be called from any other dissector?
*/
static void
-dissect_wtp_fromwap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_wtp_fromwtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "WTLS+WTP+WSP" );
/* Register the protocol with Ethereal */
void
proto_register_wtp(void)
-{
+{
/* Setup list of header fields */
static hf_register_info hf[] = {
{ &hf_wtp_header_sub_pdu_size,
- { "Sub PDU size",
+ { "Sub PDU size",
"wtp.sub_pdu_size",
- FT_BYTES, BASE_HEX, NULL, 0x0,
- "Size of Sub-PDU", HFILL
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Size of Sub-PDU (bytes)", HFILL
}
},
{ &hf_wtp_header_flag_continue,
- { "Continue Flag",
+ { "Continue Flag",
"wtp.continue_flag",
- FT_BOOLEAN, 8, TFS( &continue_truth ), 0x80,
+ FT_BOOLEAN, 8, TFS( &continue_truth ), 0x80,
"Continue Flag", HFILL
}
},
{ &hf_wtp_header_pdu_type,
- { "PDU Type",
+ { "PDU Type",
"wtp.pdu_type",
FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x78,
"PDU Type", HFILL
}
},
{ &hf_wtp_header_flag_Trailer,
- { "Trailer Flags",
+ { "Trailer Flags",
"wtp.trailer_flags",
FT_UINT8, BASE_HEX, VALS( vals_transaction_trailer ), 0x06,
"Trailer Flags", HFILL
}
},
{ &hf_wtp_header_flag_RID,
- { "Re-transmission Indicator",
+ { "Re-transmission Indicator",
"wtp.RID",
FT_BOOLEAN, 8, TFS( &RID_truth ), 0x01,
"Re-transmission Indicator", HFILL
}
},
{ &hf_wtp_header_flag_TID_response,
- { "TID Response",
+ { "TID Response",
"wtp.TID.response",
FT_BOOLEAN, 16, TFS( &tid_response_truth ), 0x8000,
"TID Response", HFILL
}
},
{ &hf_wtp_header_flag_TID,
- { "Transaction ID",
+ { "Transaction ID",
"wtp.TID",
FT_UINT16, BASE_HEX, NULL, 0x7FFF,
"Transaction ID", HFILL
}
},
{ &hf_wtp_header_Inv_version,
- { "Version",
+ { "Version",
"wtp.header.version",
FT_UINT8, BASE_HEX, VALS( vals_version ), 0xC0,
"Version", HFILL
}
},
{ &hf_wtp_header_Inv_flag_TIDNew,
- { "TIDNew",
+ { "TIDNew",
"wtp.header.TIDNew",
FT_BOOLEAN, 8, TFS( &TIDNew_truth ), 0x20,
"TIDNew", HFILL
}
},
{ &hf_wtp_header_Inv_flag_UP,
- { "U/P flag",
+ { "U/P flag",
"wtp.header.UP",
FT_BOOLEAN, 8, TFS( &UP_truth ), 0x10,
"U/P Flag", HFILL
}
},
{ &hf_wtp_header_Inv_Reserved,
- { "Reserved",
+ { "Reserved",
"wtp.inv.reserved",
FT_UINT8, BASE_HEX, NULL, 0x0C,
"Reserved", HFILL
}
},
{ &hf_wtp_header_Inv_TransactionClass,
- { "Transaction Class",
+ { "Transaction Class",
"wtp.inv.transaction_class",
FT_UINT8, BASE_HEX, VALS( vals_transaction_classes ), 0x03,
"Transaction Class", HFILL
}
},
{ &hf_wtp_header_Ack_flag_TVETOK,
- { "Tve/Tok flag",
+ { "Tve/Tok flag",
"wtp.ack.tvetok",
FT_BOOLEAN, 8, TFS( &TVETOK_truth ), 0x04,
"Tve/Tok flag", HFILL
}
},
{ &hf_wtp_header_Abort_type,
- { "Abort Type",
+ { "Abort Type",
"wtp.abort.type",
FT_UINT8, BASE_HEX, VALS ( vals_abort_type ), 0x07,
"Abort Type", HFILL
}
},
{ &hf_wtp_header_Abort_reason_provider,
- { "Abort Reason",
+ { "Abort Reason",
"wtp.abort.reason.provider",
FT_UINT8, BASE_HEX, VALS ( vals_abort_reason_provider ), 0x00,
"Abort Reason", HFILL
},
/* Assume WSP is the user and use its reason codes */
{ &hf_wtp_header_Abort_reason_user,
- { "Abort Reason",
+ { "Abort Reason",
"wtp.abort.reason.user",
FT_UINT8, BASE_HEX, VALS ( vals_wsp_reason_codes ), 0x00,
"Abort Reason", HFILL
}
},
{ &hf_wtp_header_sequence_number,
- { "Packet Sequence Number",
+ { "Packet Sequence Number",
"wtp.header.sequence",
- FT_UINT8, BASE_HEX, NULL, 0x00,
+ FT_UINT8, BASE_DEC, NULL, 0x00,
"Packet Sequence Number", HFILL
}
},
{ &hf_wtp_header_missing_packets,
- { "Missing Packets",
+ { "Missing Packets",
"wtp.header.missing_packets",
- FT_UINT8, BASE_HEX, NULL, 0x00,
+ FT_UINT8, BASE_DEC, NULL, 0x00,
"Missing Packets", HFILL
}
},
{ &hf_wtp_header_variable_part,
- { "Header: Variable part",
+ { "Header: Variable part",
"wtp.header_variable_part",
- FT_BYTES, BASE_HEX, NULL, 0x0,
+ FT_BYTES, BASE_HEX, NULL, 0x0,
"Variable part of the header", HFILL
}
},
{ &hf_wtp_data,
- { "Data",
+ { "Data",
"wtp.header_data",
- FT_BYTES, BASE_HEX, NULL, 0x0,
+ FT_BYTES, BASE_HEX, NULL, 0x0,
"Data", HFILL
}
},
{ &hf_wtp_tpi_type,
- { "TPI",
+ { "TPI",
"wtp.tpi",
FT_UINT8, BASE_HEX, VALS(vals_tpi_type), 0x00,
"Identification of the Transport Information Item", HFILL
}
},
{ &hf_wtp_tpi_psn,
- { "Packet sequence number",
+ { "Packet sequence number",
"wtp.tpi.psn",
FT_UINT8, BASE_DEC, NULL, 0x00,
"Sequence number of this packet", HFILL
}
},
{ &hf_wtp_tpi_opt,
- { "Option",
+ { "Option",
"wtp.tpi.opt",
FT_UINT8, BASE_HEX, VALS(vals_tpi_opt), 0x00,
"The given option for this TPI", HFILL
}
},
{ &hf_wtp_tpi_optval,
- { "Option Value",
+ { "Option Value",
"wtp.tpi.opt.val",
FT_NONE, BASE_NONE, NULL, 0x00,
"The value that is supplied with this option", HFILL
}
},
{ &hf_wtp_tpi_info,
- { "Information",
+ { "Information",
"wtp.tpi.info",
FT_NONE, BASE_NONE, NULL, 0x00,
"The information being send by this TPI", HFILL
{ &hf_wtp_fragment_error,
{ "Defragmentation error",
"wtp.fragment.error",
- FT_NONE, BASE_NONE, NULL, 0x0,
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
"Defragmentation error due to illegal fragments", HFILL
}
},
{ &hf_wtp_fragment,
{ "WTP Fragment",
"wtp.fragment",
- FT_NONE, BASE_NONE, NULL, 0x0,
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
"WTP Fragment", HFILL
}
},
}
},
};
-
+
/* Setup protocol subtree array */
static gint *ett[] = {
&ett_wtp,
+ &ett_wtp_sub_pdu_tree,
&ett_header,
&ett_tpilist,
&ett_wsp_fragments,
/* Register the protocol name and description */
proto_wtp = proto_register_protocol(
- "Wireless Transaction Protocol", /* protocol name for use by ethereal */
+ "Wireless Transaction Protocol", /* protocol name for use by ethereal */
"WTP", /* short version of name */
- "wap-wsp-wtp" /* Abbreviated protocol name, should Match IANA
+ "wtp" /* Abbreviated protocol name, should Match IANA
< URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
*/
);
proto_register_field_array(proto_wtp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
- register_dissector("wtp", dissect_wtp_fromwap, proto_wtp);
+ register_dissector("wtp-wtls", dissect_wtp_fromwtls, proto_wtp);
register_dissector("wtp-udp", dissect_wtp_fromudp, proto_wtp);
register_init_routine(wtp_defragment_init);
-};
+}
void
proto_reg_handoff_wtp(void)
wtp_fromudp_handle = find_dissector("wtp-udp");
dissector_add("udp.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
+ dissector_add("smpp.udh.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
}