diff options
-rw-r--r-- | AUTHORS | 4 | ||||
-rw-r--r-- | epan/dissectors/Makefile.common | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-cmpp.c | 1007 |
3 files changed, 1012 insertions, 0 deletions
@@ -2691,6 +2691,10 @@ Fulko Hew <fulko.hew [AT] gmail.com> { Link Control) WAN protocol dissection } +Andy Chu <chu.dev[AT]gmail.com> { + China Mobile Point to Point +} + and by: Pavel Roskin <proski [AT] gnu.org> diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 559e2f8dbc..b51a57943b 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -254,6 +254,7 @@ CLEAN_DISSECTOR_SRC = \ packet-clearcase.c \ packet-clip.c \ packet-clnp.c \ + packet-cmpp.c \ packet-componentstatus.c \ packet-cops.c \ packet-cosine.c \ diff --git a/epan/dissectors/packet-cmpp.c b/epan/dissectors/packet-cmpp.c new file mode 100644 index 0000000000..e4e8ca2ffe --- /dev/null +++ b/epan/dissectors/packet-cmpp.c @@ -0,0 +1,1007 @@ +/* packet-cmpp.c + * Routines for China Mobile Point to Point dissection + * Copyright 2007, Andy Chu <chu.dev@gmail.com> + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <epan/packet.h> +#include <epan/dissectors/packet-tcp.h> + +#define CMPP_VERSIONBUF 6 +#define CMPP_TIMESTAMPBUFF 15 +#define CMPP_FIX_HEADER_LENGTH 12 +#define CMPP_DELIVER_REPORT_LEN 71 + +/* These are not registered with IANA */ +#define CMPP_SP_LONG_PORT 7890 +#define CMPP_SP_SHORT_PORT 7900 +#define CMPP_ISMG_LONG_PORT 7930 +#define CMPP_ISMG_SHORT_PORT 9168 + +/* Forward declaration we need below */ +void proto_reg_handoff_cmpp(void); + +/* Initialize the protocol and registered fields */ +static gint proto_cmpp = -1; + +/* These are the fix header field */ +static gint hf_cmpp_Total_Length = -1; +static gint hf_cmpp_Command_Id = -1; +static gint hf_cmpp_Sequence_Id = -1; + +/* CMPP_CONNECT */ +static gint hf_cmpp_connect_Source_Addr = -1; +static gint hf_cmpp_connect_AuthenticatorSource = -1; +static gint hf_cmpp_Version = -1; +static gint hf_cmpp_connect_Timestamp = -1; + +/* CMPP_CONNECT_RESP */ +static gint hf_cmpp_connect_resp_status = -1; +static gint hf_cmpp_connect_resp_AuthenticatorISMG = -1; + +/* CMPP_SUBMIT */ +static gint hf_cmpp_submit_pk_total = -1; +static gint hf_cmpp_submit_pk_number = -1; +static gint hf_cmpp_submit_Msg_level = -1; +static gint hf_cmpp_submit_Fee_UserType = -1; +static gint hf_cmpp_submit_Fee_terminal_Id = -1; +static gint hf_cmpp_submit_Fee_terminal_type = -1; +static gint hf_cmpp_submit_Msg_src = -1; +static gint hf_cmpp_submit_FeeType = -1; +static gint hf_cmpp_submit_FeeCode = -1; +static gint hf_cmpp_submit_Valld_Time = -1; +static gint hf_cmpp_submit_At_Time = -1; +static gint hf_cmpp_submit_Src_Id = -1; +static gint hf_cmpp_submit_DestUsr_tl = -1; +static gint hf_cmpp_submit_Dest_terminal_type = -1; +static gint hf_cmpp_submit_Registered_Delivery = -1; + +/* Field common in CMPP_SUBMIT and CMPP_DELIVER */ +static gint hf_cmpp_Dest_terminal_Id = -1; +static gint hf_cmpp_Service_Id = -1; +static gint hf_cmpp_TP_pId = -1; +static gint hf_cmpp_TP_udhi = -1; +static gint hf_cmpp_Msg_Fmt = -1; +static gint hf_cmpp_Msg_Length = -1; +static gint hf_cmpp_Msg_Content = -1; +static gint hf_cmpp_LinkID = -1; + +/* CMPP_SUBMIT_RESP */ +static gint hf_cmpp_submit_resp_Result = -1; + +/* CMPP_QUERY */ +/* CMPP_QUERY_RESP */ +/* TODO implement CMPP_QUERY and CMPP_QUERY_RESP */ + +/* CMPP_DELIVER */ +static gint hf_cmpp_deliver_Dest_Id = -1; +static gint hf_cmpp_deliver_Src_terminal_Id = -1; +static gint hf_cmpp_deliver_Src_terminal_type = -1; +static gint hf_cmpp_deliver_Registered_Delivery = -1; + +static gint hf_cmpp_deliver_resp_Result = -1; + +/* CMPP Deliver Report */ +static gint hf_cmpp_deliver_Report = -1; +static gint hf_cmpp_deliver_Report_Stat = -1; +static gint hf_cmpp_deliver_Report_Submit_time = -1; +static gint hf_cmpp_deliver_Report_Done_time = -1; +static gint hf_cmpp_deliver_Report_SMSC_sequence = -1; + +/* Msg_Id field */ +static gint hf_cmpp_msg_id = -1; +static gint hf_msg_id_timestamp = -1; +static gint hf_msg_id_ismg_code = -1; +static gint hf_msg_id_sequence_id = -1; + +static gboolean cmpp_desegment = TRUE; + +/* + * Value-arrays for field-contents + */ +#define CMPP_CONNECT 0x00000001 +#define CMPP_CONNECT_RESP 0x80000001 +#define CMPP_TERMINATE 0x00000002 +#define CMPP_TERMINATE_RESP 0x80000002 +#define CMPP_SUBMIT 0x00000004 +#define CMPP_SUBMIT_RESP 0x80000004 +#define CMPP_DELIVER 0x00000005 +#define CMPP_DELIVER_RESP 0x80000005 +#define CMPP_QUERY 0x00000006 +#define CMPP_QUERY_RESP 0x80000006 +#define CMPP_CANCEL 0x00000007 +#define CMPP_CANCEL_RESP 0x80000007 +#define CMPP_ACTIVE_TEST 0x00000008 +#define CMPP_ACTIVE_TEST_RESP 0x80000008 +#define CMPP_FWD 0x00000009 +#define CMPP_FWD_RESP 0x80000009 +#define CMPP_MT_ROUTE 0x00000010 +#define CMPP_MO_ROUTE 0x00000011 +#define CMPP_GET_MT_ROUTE 0x00000012 +#define CMPP_MT_ROUTE_UPDATE 0x00000013 +#define CMPP_MO_ROUTE_UPDATE 0x00000014 +#define CMPP_PUSH_MT_ROUTE_UPDATE 0x00000015 +#define CMPP_PUSH_MO_ROUTE_UPDATE 0x00000016 +#define CMPP_GET_MO_ROUTE 0x00000017 +#define CMPP_MT_ROUTE_RESP 0x80000010 +#define CMPP_MO_ROUTE_RESP 0x80000011 +#define CMPP_GET_MT_ROUTE_RESP 0x80000012 +#define CMPP_MT_ROUTE_UPDATE_RESP 0x80000013 +#define CMPP_MO_ROUTE_UPDATE_RESP 0x80000014 +#define CMPP_PUSH_MT_ROUTE_UPDATE_RESP 0x80000015 +#define CMPP_PUSH_MO_ROUTE_UPDATE_RESP 0x80000016 +#define CMPP_GET_MO_ROUTE_RESP 0x80000017 +static const value_string vals_command_Id[] = { /* Operation */ + { CMPP_CONNECT, "CMPP_CONNECT" }, + { CMPP_CONNECT_RESP, "CMPP_CONNECT_RESP" }, + { CMPP_TERMINATE, "CMPP_TERMINATE" }, + { CMPP_TERMINATE_RESP, "CMPP_TERMINATE_RESP" }, + { CMPP_SUBMIT, "CMPP_SUBMIT" }, + { CMPP_SUBMIT_RESP, "CMPP_SUBMIT_RESP" }, + { CMPP_DELIVER, "CMPP_DELIVER" }, + { CMPP_DELIVER_RESP, "CMPP_DELIVER_RESP" }, + { CMPP_QUERY, "CMPP_QUERY" }, + { CMPP_QUERY_RESP, "CMPP_QUERY" }, + { CMPP_CANCEL, "CMPP_CANCEL" }, + { CMPP_CANCEL_RESP, "CMPP_CANCEL_RESP" }, + { CMPP_ACTIVE_TEST, "CMPP_ACTIVE_TEST" }, + { CMPP_ACTIVE_TEST_RESP, "CMPP_ACTIVE_TEST_RESP" }, + { CMPP_FWD, "CMPP_FWD" }, + { CMPP_FWD_RESP, "CMPP_FWD_RESP" }, + { CMPP_MT_ROUTE, "CMPP_MT_ROUTE" }, + { CMPP_MO_ROUTE, "CMPP_MO_ROUTE" }, + { CMPP_GET_MT_ROUTE, "CMPP_GET_MT_ROUTE" }, + { CMPP_MT_ROUTE_UPDATE, "CMPP_MT_ROUTE_UPDATE" }, + { CMPP_MO_ROUTE_UPDATE, "CMPP_MO_ROUTE_UPDATE" }, + { CMPP_PUSH_MT_ROUTE_UPDATE, "CMPP_PUSH_MT_ROUTE_UPDATE" }, + { CMPP_PUSH_MO_ROUTE_UPDATE, "CMPP_PUSH_MO_ROUTE_UPDATE" }, + { CMPP_GET_MO_ROUTE, "CMPP_GET_MO_ROUTE" }, + { CMPP_MT_ROUTE_RESP, "CMPP_MT_ROUTE_RESP" }, + { CMPP_MO_ROUTE_RESP, "CMPP_MO_ROUTE_RESP" }, + { CMPP_GET_MT_ROUTE_RESP, "CMPP_GET_MT_ROUTE_RESP" }, + { CMPP_MT_ROUTE_UPDATE_RESP, "CMPP_MT_ROUTE_UPDATE_RESP" }, + { CMPP_MO_ROUTE_UPDATE_RESP, "CMPP_MO_ROUTE_UPDATE_RESP" }, + { CMPP_PUSH_MT_ROUTE_UPDATE_RESP, "CMPP_PUSH_MT_ROUTE_UPDATE_RESP" }, + { CMPP_PUSH_MO_ROUTE_UPDATE_RESP, "CMPP_PUSH_MO_ROUTE_UPDATE_RESP" }, + { CMPP_GET_MO_ROUTE_RESP, "CMPP_GET_MO_ROUTE_RESP" }, + { 0, NULL } +}; + +static const value_string vals_connect_resp_status[] = { /* Connection Status */ + { 0, "Correct" }, + { 1, "Message structure error" }, + { 2, "Illegal source address" }, + { 3, "Authenticate error" }, + { 4, "Version too high" }, + { 0, NULL } +}; + +static const value_string vals_submit_Fee_UserType[] = { /* Submit Fee_UserType */ + { 0, "Charging destination MSISDN" }, + { 1, "Charging source MSISDN" }, + { 2, "Charging SP" }, + { 3, "Unuse, Charge info from Fee_terminal_Id" }, + { 0, NULL } +}; + +static const value_string vals_Msg_Fmt[] = { /* Message Format */ + { 0, "ASCII" }, + { 3, "Short message card" }, /* TODO find the correct string of this value */ + { 4, "Binary data" }, + { 8, "UCS2 encoding" }, + {15, "GB encoding" }, + { 0, NULL } +}; + +/* Submit Response Result */ +static const value_string vals_Submit_Resp_Result[] = { + { 0, "Correct" }, + { 1, "Message format error" }, + { 2, "Command error" }, + { 3, "Repeat sequence id" }, + { 4, "Incorrect message length" }, + { 5, "Incorrect fee code" }, + { 6, "Message too long" }, + { 7, "Incorrect service id" }, + { 8, "Bandwidth error" }, + { 9, "Gateway does not service this charging number" }, + {10, "Incorrect Src_Id" }, + {11, "Incorrect Msg_src" }, + {12, "Incorrect Fee_terminal_Id" }, + {13, "Incorrect Dest_terminal_Id" }, + { 0, NULL } +}; + +/* Deliver Response Result */ +static const value_string vals_Deliver_Resp_Result[] = { + { 0, "Correct" }, + { 1, "Message format error" }, + { 2, "Command error" }, + { 3, "Repeat sequence id" }, + { 4, "Incorrect message length" }, + { 5, "Incorrect fee code" }, + { 6, "Message too long" }, + { 7, "Incorrect service id" }, + { 8, "Bandwidth error" }, + { 0, NULL } +}; + +/* Initialize the subtree pointers */ +static gint ett_cmpp = -1; +static gint ett_msg_id = -1; +static gint ett_deliver_report = -1; + +/* Helper functions */ + +static char* +cmpp_octet_string(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset, gint length) +{ + char *display; + + display = (char *)tvb_get_ephemeral_string(tvb, offset, length); + proto_tree_add_string(tree, field, tvb, offset, length, display); + return display; +} + +static char* +cmpp_version(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset) +{ + gint8 version, major, minor; + char *strval; + + version = tvb_get_guint8(tvb, offset); + minor = version & 0x0F; + major = (version & 0xF0) >> 4; + strval = ep_alloc(CMPP_VERSIONBUF); + g_snprintf(strval, CMPP_VERSIONBUF, "%02u.%02u", major, minor); + /* TODO: the version should be added as a uint_format */ + proto_tree_add_string(tree, field, tvb, offset, 1, strval); + return strval; +} + +static char* +cmpp_timestamp(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset) +{ + gint8 month, day, hour, minute, second; + gint32 timevalue; + char *strval; + + timevalue = tvb_get_ntohl(tvb, offset); + second = timevalue % 100; + timevalue /= 100; + minute = timevalue % 100; + timevalue /= 100; + hour = timevalue % 100; + timevalue /= 100; + day = timevalue % 100; + month = timevalue / 100; + strval = ep_alloc(CMPP_TIMESTAMPBUFF); + g_snprintf(strval, CMPP_TIMESTAMPBUFF, "%02u/%02u %02u:%02u:%02u", month, day, + hour, minute, second); + proto_tree_add_string(tree, field, tvb, offset, 4, strval); + return strval; +} + +/* TODO: most calls to these (except those that use the return value) should + * be replaced by calls to proto_tree_add_item(). + */ +static guint8 +cmpp_uint1(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset) +{ + guint8 value; + value = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, field, tvb, offset, 1, value); + return value; +} + +static guint16 +cmpp_uint2(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset) +{ + guint16 value; + value = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, field, tvb, offset, 2, value); + return value; +} + +static gint32 +cmpp_uint4(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset) +{ + gint32 value; + value = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(tree, field, tvb, offset, 4, value); + return value; +} + +static gboolean +cmpp_boolean(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset) +{ + gint8 value; + value = tvb_get_guint8(tvb, offset); + proto_tree_add_boolean(tree, field, tvb, offset, 1, value); + if (value == 1) + return TRUE; + return FALSE; +} + +static void +cmpp_msg_id(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset) +{ + guint8 month,day,hour,minute,second; + guint32 ismg_code; + proto_item *sub_tree; + char *strval; + + sub_tree = proto_tree_add_item(tree, field, tvb, offset, 8, FALSE); + proto_item_add_subtree(sub_tree, ett_msg_id); + + month = (tvb_get_guint8(tvb, offset) & 0xF0) >> 4; + day = (tvb_get_ntohs(tvb, offset) & 0x0F80) >> 7; + hour = (tvb_get_guint8(tvb, offset + 1) & 0x7C) >> 2; + minute = (tvb_get_ntohs(tvb, offset + 1) & 0x03F0) >> 4; + second = (tvb_get_ntohs(tvb, offset + 2) & 0x0FC0) >> 6; + strval = ep_alloc(CMPP_TIMESTAMPBUFF); + g_snprintf(strval, CMPP_TIMESTAMPBUFF, "%02u/%02u %02u:%02u:%02u", month, day, + hour, minute, second); + + ismg_code = (tvb_get_ntohl(tvb, offset + 3) & 0x3FFFFF00) >> 16; + + proto_tree_add_string(sub_tree, hf_msg_id_timestamp, tvb, offset, 4, strval); + proto_tree_add_uint(sub_tree, hf_msg_id_ismg_code, tvb, offset + 3, 3, ismg_code); + cmpp_uint2(sub_tree, tvb, hf_msg_id_sequence_id, offset + 6); +} + +static void +cmpp_connect(proto_tree *tree, tvbuff_t *tvb) +{ + int offset; + offset = CMPP_FIX_HEADER_LENGTH; + cmpp_octet_string(tree, tvb, hf_cmpp_connect_Source_Addr, offset, 6); + offset += 6; + proto_tree_add_string(tree, hf_cmpp_connect_AuthenticatorSource, tvb, offset, 16, "MD5 Hash"); + offset += 16; + cmpp_version(tree, tvb, hf_cmpp_Version, offset); + offset += 1; + cmpp_timestamp(tree, tvb, hf_cmpp_connect_Timestamp, offset); +} + + +static void +cmpp_connect_resp(proto_tree *tree, tvbuff_t *tvb) +{ + int offset; + offset = CMPP_FIX_HEADER_LENGTH; + cmpp_uint4(tree, tvb, hf_cmpp_connect_resp_status, offset); + offset += 4; + proto_tree_add_string(tree, hf_cmpp_connect_resp_AuthenticatorISMG, tvb, offset, 16, "MD5 Hash"); + offset += 16; + cmpp_version(tree, tvb, hf_cmpp_Version, offset); +} + +static void +cmpp_submit(proto_tree *tree, tvbuff_t *tvb) +{ + int offset, i; + guint8 msg_format, destUsr, msgLen; + offset = CMPP_FIX_HEADER_LENGTH; + cmpp_msg_id(tree, tvb, hf_cmpp_msg_id, offset); + offset += 8; + cmpp_uint1(tree, tvb, hf_cmpp_submit_pk_total, offset); + offset++; + cmpp_uint1(tree, tvb, hf_cmpp_submit_pk_number, offset); + offset++; + cmpp_boolean(tree, tvb, hf_cmpp_submit_Registered_Delivery, offset); + offset++; + cmpp_uint1(tree, tvb, hf_cmpp_submit_Msg_level, offset); + offset++; + cmpp_octet_string(tree, tvb, hf_cmpp_Service_Id, offset, 10); + offset += 10; + cmpp_uint1(tree, tvb, hf_cmpp_submit_Fee_UserType, offset); + offset++; + cmpp_octet_string(tree, tvb, hf_cmpp_submit_Fee_terminal_Id, offset, 32); + offset+=32; + cmpp_boolean(tree, tvb, hf_cmpp_submit_Fee_terminal_type, offset); + offset++; + cmpp_uint1(tree, tvb, hf_cmpp_TP_pId, offset); + offset++; + cmpp_uint1(tree, tvb, hf_cmpp_TP_udhi, offset); + offset++; + msg_format = cmpp_uint1(tree, tvb, hf_cmpp_Msg_Fmt, offset); + offset++; + cmpp_octet_string(tree, tvb, hf_cmpp_submit_Msg_src, offset, 6); + offset += 6; + cmpp_octet_string(tree, tvb, hf_cmpp_submit_FeeType, offset, 2); + offset += 2; + cmpp_octet_string(tree, tvb, hf_cmpp_submit_FeeCode, offset, 6); + offset += 6; + + /* TODO create function to handle SMPP time format */ + cmpp_octet_string(tree, tvb, hf_cmpp_submit_Valld_Time, offset, 17); + offset += 17; + cmpp_octet_string(tree, tvb, hf_cmpp_submit_At_Time, offset, 17); + offset += 17; + + cmpp_octet_string(tree, tvb, hf_cmpp_submit_Src_Id, offset, 17); + offset += 21; + destUsr = cmpp_uint1(tree, tvb, hf_cmpp_submit_DestUsr_tl, offset); + offset++; + + /* Loop through each destination address */ + for(i = 0; i < destUsr; i++) + { + cmpp_octet_string(tree, tvb, hf_cmpp_Dest_terminal_Id, offset, 32); + offset += 32; + } + + cmpp_boolean(tree, tvb, hf_cmpp_submit_Dest_terminal_type, offset); + offset++; + msgLen = cmpp_uint1(tree, tvb, hf_cmpp_Msg_Length, offset); + offset++; + proto_tree_add_string(tree, hf_cmpp_Msg_Content, tvb, offset, msgLen, "SMS Messages"); + offset += msgLen; + cmpp_octet_string(tree, tvb, hf_cmpp_LinkID, offset, 20); +} + +static void +cmpp_submit_resp(proto_tree *tree, tvbuff_t *tvb) +{ + int offset; + offset = CMPP_FIX_HEADER_LENGTH; + cmpp_msg_id(tree, tvb, hf_cmpp_msg_id, offset); + offset += 8; + cmpp_uint4(tree, tvb, hf_cmpp_submit_resp_Result, offset); +} + +static void +cmpp_deliver_report(proto_tree *tree, tvbuff_t *tvb, gint field, guint offset) +{ + proto_item *sub_tree; + sub_tree = proto_tree_add_item(tree, field, tvb, offset, CMPP_DELIVER_REPORT_LEN, FALSE); + proto_item_add_subtree(sub_tree, ett_deliver_report); + cmpp_msg_id(sub_tree, tvb, hf_cmpp_msg_id, offset); + offset += 8; + cmpp_octet_string(sub_tree, tvb, hf_cmpp_deliver_Report_Stat, offset, 7); + offset += 7; + cmpp_octet_string(sub_tree, tvb, hf_cmpp_deliver_Report_Submit_time, offset, 10); + offset += 10; + cmpp_octet_string(sub_tree, tvb, hf_cmpp_deliver_Report_Done_time, offset, 10); + offset += 10; + cmpp_octet_string(sub_tree, tvb, hf_cmpp_Dest_terminal_Id, offset, 32); + offset += 32; + cmpp_uint4(sub_tree, tvb, hf_cmpp_deliver_Report_SMSC_sequence, offset); +} + +static void +cmpp_deliver(proto_tree *tree, tvbuff_t *tvb) +{ + guint offset, msgLen; + gboolean report; + offset = CMPP_FIX_HEADER_LENGTH; + cmpp_msg_id(tree, tvb, hf_cmpp_msg_id, offset); + offset += 8; + cmpp_octet_string(tree, tvb, hf_cmpp_deliver_Dest_Id, offset, 21); + offset += 21; + cmpp_octet_string(tree, tvb, hf_cmpp_Service_Id, offset, 10); + offset += 10; + cmpp_uint1(tree, tvb, hf_cmpp_TP_pId, offset); + offset++; + cmpp_uint1(tree, tvb, hf_cmpp_TP_udhi, offset); + offset++; + cmpp_uint1(tree, tvb, hf_cmpp_Msg_Fmt, offset); + offset++; + cmpp_octet_string(tree, tvb, hf_cmpp_deliver_Src_terminal_Id, offset, 32); + offset += 32; + cmpp_boolean(tree, tvb, hf_cmpp_deliver_Src_terminal_type, offset); + offset++; + report = cmpp_boolean(tree, tvb, hf_cmpp_deliver_Registered_Delivery, offset); + offset++; + msgLen = cmpp_uint1(tree, tvb, hf_cmpp_Msg_Length, offset); + offset++; + if (report == FALSE) + proto_tree_add_string(tree, hf_cmpp_Msg_Content, tvb, offset, msgLen, "SMS Messages"); + else + cmpp_deliver_report(tree, tvb, hf_cmpp_deliver_Report, offset); + offset += msgLen; + cmpp_octet_string(tree, tvb, hf_cmpp_LinkID, offset, 20); +} + +static void +cmpp_deliver_resp(proto_tree *tree, tvbuff_t *tvb) +{ + int offset; + offset = CMPP_FIX_HEADER_LENGTH; + cmpp_msg_id(tree, tvb, hf_cmpp_msg_id, offset); + offset += 8; + /* TODO implement the result field here */ + cmpp_uint4(tree, tvb, hf_cmpp_deliver_resp_Result, offset); +} + +/* Code to actually dissect the packets */ +static void +dissect_cmpp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + +/* Set up structures needed to add the protocol subtree and manage it */ + proto_item *ti; + proto_tree *cmpp_tree; + guint command_id; + guint tvb_len; + guint total_length; + const gchar *command_str; /* Header command string */ + + /* Get the length of the PDU */ + tvb_len = tvb_length(tvb); + /* if the length of the tvb is shorder then the cmpp header length exit */ + if (tvb_len < CMPP_FIX_HEADER_LENGTH) + return; + + total_length = tvb_get_ntohl(tvb, 0); /* Get the pdu length */ + command_id = tvb_get_ntohl(tvb, 4); /* get the pdu command id */ + + if (match_strval(command_id, vals_command_Id) == NULL) + { + col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown command_id %u", + command_id); + return; + } + + command_str = val_to_str(command_id, vals_command_Id, + "(Unknown CMPP Operation 0x%08X)"); + + /* tvb has less data then the PDU Header status, return */ + if (tvb_len < total_length) + { + col_append_fstr(pinfo->cinfo, COL_INFO, "%s pdu length (%u) < Total_Length (%u)", + command_str, tvb_len, total_length); + return; + } + + /* 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, "CMPP"); + + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_append_fstr(pinfo->cinfo, COL_INFO, "%s. ", command_str); + } + + if (tree) + { + + ti = proto_tree_add_item(tree, proto_cmpp, tvb, 0, -1, FALSE); + + cmpp_tree = proto_item_add_subtree(ti, ett_cmpp); + + /* Add the fix header informations to the tree */ + cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Total_Length, 0); + cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Command_Id, 4); + cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Sequence_Id, 8); + + switch(command_id) + { + case CMPP_CONNECT: + cmpp_connect(cmpp_tree, tvb); + break; + case CMPP_CONNECT_RESP: + cmpp_connect_resp(cmpp_tree, tvb); + break; + /* CMPP_TERMINATE and CMPP_TERMINATE_RESP don't have msg body */ + case CMPP_TERMINATE: + case CMPP_TERMINATE_RESP: + break; + case CMPP_SUBMIT: + cmpp_submit(cmpp_tree, tvb); + break; + case CMPP_SUBMIT_RESP: + cmpp_submit_resp(cmpp_tree, tvb); + break; + case CMPP_DELIVER: + cmpp_deliver(cmpp_tree, tvb); + break; + case CMPP_DELIVER_RESP: + cmpp_deliver_resp(cmpp_tree, tvb); + break; + default: + /* Implement the rest of the protocol here */ + break; + } + } +} + + +/* Register the protocol with Wireshark */ + +/* Get the CMPP PDU Length */ +static guint +get_cmpp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, gint offset) +{ + return tvb_get_ntohl(tvb, offset); +} + + +static int +dissect_cmpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + guint total_length, command_id, sequence_id; /* Fix Header field */ + /* Check that there's enough data */ + if (tvb_length(tvb) < CMPP_FIX_HEADER_LENGTH) + return 0; + + /* Get some values from the packet header, probably using tvb_get_*() */ + total_length = tvb_get_ntohl(tvb, 0); /* Get the pdu length */ + command_id = tvb_get_ntohl(tvb, 4); /* get the pdu command id */ + sequence_id = tvb_get_ntohl(tvb, 8); /* get the sequence id */ + + if (match_strval(command_id, vals_command_Id) == NULL) + /* This packet does not appear to belong to CMPP. + * Return 0 to give another dissector a chance to dissect it. + */ + return 0; + + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + + tcp_dissect_pdus(tvb, pinfo, tree, cmpp_desegment, CMPP_FIX_HEADER_LENGTH, + get_cmpp_pdu_len, dissect_cmpp_tcp_pdu); + + /* Return the amount of data this dissector was able to dissect */ + return tvb_length(tvb); + +} + + +/* this format is require because a script is used to build the C function + that calls all the protocol registration. +*/ +void +proto_register_cmpp(void) { + +/* Setup list of header fields See Section 1.6.1 for details*/ + static hf_register_info hf[] = { + { &hf_cmpp_Total_Length, + { "Total Length", "cmpp.Total_Length", + FT_UINT32, BASE_DEC, NULL, 0x00, + "Total length of the CMPP PDU.", + HFILL } + }, + { &hf_cmpp_Command_Id, + { "Command Id", "cmpp.Command_Id", + FT_UINT32, BASE_HEX, VALS(vals_command_Id), 0x00, + "Command Id of the CMPP messages", + HFILL } + }, + { &hf_cmpp_Sequence_Id, + { "Sequence Id", "cmpp.Sequence_Id", + FT_UINT32, BASE_DEC, NULL, 0x00, + "Sequence Id of the CMPP messages", + HFILL } + }, + { &hf_cmpp_connect_Source_Addr, + { "Source Addr", "cmpp.connect.Source_Addr", + FT_STRING, BASE_NONE, NULL, 0x00, + "Source Address, the SP_Id", + HFILL } + }, + { &hf_cmpp_connect_AuthenticatorSource, + { "Authenticator Source", "cmpp.connect.AuthenticatorSource", + FT_STRING, BASE_NONE, NULL, 0x00, + "Authenticator source, MD5(Source_addr + 9 zero + shared secret + timestamp)", + HFILL } + }, + + { &hf_cmpp_Version, + { "Version", "cmpp.Version", + FT_STRING, BASE_NONE, NULL, 0x00, + "CMPP Version", + HFILL } + }, + { &hf_cmpp_connect_Timestamp, + { "Timestamp", "cmpp.connect.Timestamp", + FT_STRING, BASE_NONE, NULL, 0x00, + "Timestamp MM/DD HH:MM:SS", + HFILL } + }, + { &hf_cmpp_connect_resp_status, + { "Connect Response Status", "cmpp.connect_resp.Status", + FT_UINT32, BASE_DEC, VALS(vals_connect_resp_status), 0x00, + "Response Status, Value higher then 4 means other error", + HFILL } + }, + { &hf_cmpp_connect_resp_AuthenticatorISMG, + { "SIMG Authenticate result", "cmpp.connect_resp.AuthenticatorISMG", + FT_STRING, BASE_NONE, NULL, 0x00, + "Authenticator result, MD5(Status + AuthenticatorSource + shared secret)", + HFILL } + }, + { &hf_cmpp_msg_id, + { "Msg_Id", "cmpp.Msg_Id", + FT_UINT64, BASE_HEX, NULL, 0x00, + "Message ID", + HFILL } + }, + { &hf_cmpp_submit_pk_total, + { "Number of Part", "cmpp.submit.Pk_total", + FT_UINT8, BASE_DEC, NULL, 0x00, + "Total number of parts of the message with the same Msg_Id, start from 1", + HFILL } + }, + { &hf_cmpp_submit_pk_number, + { "Part Number", "cmpp.submit.Pk_number", + FT_UINT8, BASE_DEC, NULL, 0x00, + "Part number of the message with the same Msg_Id, start from 1", + HFILL } + }, + { &hf_msg_id_timestamp, + { "Timestamp", "cmpp.Msg_Id.timestamp", + FT_STRING, BASE_NONE, NULL, 0x00, + "Timestamp MM/DD HH:MM:SS Bit 64 ~ 39", + HFILL } + }, + { &hf_msg_id_ismg_code, + { "ISMG Code", "cmpp.Msg_Id.ismg_code", + FT_UINT32, BASE_DEC, NULL, 0x00, + "ISMG Code, bit 38 ~ 17", + HFILL } + }, + { &hf_msg_id_sequence_id, + { "Msg_Id sequence Id", "cmpp.Msg_Id.sequence_id", + FT_UINT16, BASE_DEC, NULL, 0x00, + "Msg_Id sequence Id, bit 16 ~ 1", + HFILL } + }, + { &hf_cmpp_submit_Registered_Delivery, + { "Registered Delivery", "cmpp.submit.Registered_Delivery", + FT_BOOLEAN, BASE_DEC, NULL, 0x00, + "Registered Delivery flag", + HFILL } + }, + { &hf_cmpp_submit_Msg_level, + { "Message Level", "cmpp.submit.Msg_level", + FT_UINT8, BASE_DEC, NULL, 0x00, + "Message Level", + HFILL } + }, + { &hf_cmpp_Service_Id, + { "Service ID", "cmpp.Servicd_Id", + FT_STRING, BASE_NONE, NULL, 0x00, + "Service ID, a mix of characters, numbers and symbol", + HFILL } + }, + { &hf_cmpp_submit_Fee_UserType, + { "Charging Informations", "cmpp.submit.Fee_UserType", + FT_UINT8, BASE_DEC, VALS(vals_submit_Fee_UserType), 0x00, + "Charging Informations, if value is 3, this field will not be used", + HFILL } + }, + { &hf_cmpp_submit_Fee_terminal_Id, + { "Fee Terminal ID", "cmpp.submit.Fee_terminal_Id", + FT_STRING, BASE_NONE, NULL, 0x00, + "Fee Terminal ID, Valid only when Fee_UserType is 3", + HFILL } + }, + { &hf_cmpp_submit_Fee_terminal_type, + { "Fake Fee Terminal", "cmpp.submit.Fee_terminal_type", + FT_BOOLEAN, BASE_DEC, NULL, 0x00, + "Fee terminal type, 0 is real, 1 is fake", + HFILL } + }, + { &hf_cmpp_TP_pId, + { "TP pId", "cmpp.TP_pId", + FT_UINT8, BASE_DEC, NULL, 0x00, + "GSM TP pId Field", + HFILL } + }, + { &hf_cmpp_TP_udhi, + { "TP udhi", "cmpp.TP_udhi", + FT_UINT8, BASE_DEC, NULL, 0x00, + "GSM TP udhi field", + HFILL } + }, + { &hf_cmpp_Msg_Fmt, + { "Message Format", "cmpp.Msg_Fmt", + FT_UINT8, BASE_DEC, VALS(vals_Msg_Fmt), 0x00, + "Message Format", + HFILL } + }, + { &hf_cmpp_submit_Msg_src, + { "Message Source SP_Id", "cmpp.submit.Msg_src", + FT_STRING, BASE_NONE, NULL, 0x00, + "Message source SP ID", + HFILL } + }, + { &hf_cmpp_submit_FeeType, /* TODO Replace this with a vals_string*/ + { "Fee Type", "cmpp.submit.FeeType", + FT_STRING, BASE_NONE, NULL, 0x00, + "Fee Type", + HFILL } + }, + { &hf_cmpp_submit_FeeCode, + { "Fee Code", "cmpp.submit.FeeCode", + FT_STRING, BASE_NONE, NULL, 0x00, + "Fee Code", + HFILL } + }, + { &hf_cmpp_submit_Valld_Time, + { "Valid time", "cmpp.submit.Valld_Time", + FT_STRING, BASE_NONE, NULL, 0x00, + "Message Valid Time, format follow SMPP 3.3", + HFILL } + }, + { &hf_cmpp_submit_At_Time, + { "Send time", "cmpp.submit.At_time", + FT_STRING, BASE_NONE, NULL, 0x00, + "Message send time, format following SMPP 3.3", + HFILL } + }, + { &hf_cmpp_submit_Src_Id, + { "Source ID", "cmpp.submit.Src_Id", + FT_STRING, BASE_NONE, NULL, 0x00, + "This value matches SMPP submit_sm source_addr field", + HFILL } + }, + { &hf_cmpp_submit_DestUsr_tl, + { "Destination Address Count", "cmpp.submit.DestUsr_tl", + FT_UINT8, BASE_DEC, NULL, 0x00, + "Number of destination address, must smaller then 100", + HFILL } + }, + { &hf_cmpp_Dest_terminal_Id, + { "Destination Address", "cmpp.Dest_terminal_Id", + FT_STRING, BASE_NONE, NULL, 0x00, + "MSISDN number which receive the SMS", + HFILL } + }, + { &hf_cmpp_submit_Dest_terminal_type, + { "Fake Destination Terminal", "cmpp.submit.Dest_terminal_type", + FT_BOOLEAN, BASE_DEC, NULL, 0x00, + "destination terminal type, 0 is real, 1 is fake", + HFILL } + }, + { &hf_cmpp_Msg_Length, + { "Message length", "cmpp.Msg_Length", + FT_UINT8, BASE_DEC, NULL, 0x00, + "SMS Message length, ASCII must be <= 160 bytes, other must be <= 140 bytes", + HFILL } + }, + { &hf_cmpp_Msg_Content, + { "Message Content", "cmpp.Msg_Content", + FT_STRING, BASE_NONE, NULL, 0x00, + "Message Content", + HFILL } + }, + { &hf_cmpp_LinkID, + { "Link ID", "cmpp.LinkID", + FT_STRING, BASE_NONE, NULL, 0x00, + "Link ID", + HFILL } + }, + { &hf_cmpp_submit_resp_Result, + { "Result", "cmpp.submit_resp.Result", + FT_UINT32, BASE_DEC, VALS(vals_Submit_Resp_Result), 0x00, + "Submit Result", + HFILL } + }, + { &hf_cmpp_deliver_Dest_Id, + { "Destination ID", "cmpp.deliver.Dest_Id", + FT_STRING, BASE_NONE, NULL, 0x00, + "SP Service ID or server number", + HFILL } + }, + { &hf_cmpp_deliver_Src_terminal_Id, + { "Src_terminal_Id", "cmpp.deliver.Src_terminal_Id", + FT_STRING, BASE_NONE, NULL, 0x00, + "Source MSISDN number, if it is deliver report, this will be the CMPP_SUBMIT destination number", + HFILL } + }, + { &hf_cmpp_deliver_Src_terminal_type, + { "Fake source terminal type", "cmpp.deliver.Src_terminal_type", + FT_BOOLEAN, BASE_DEC, NULL, 0x00, + "Type of the source terminal, can be 0 (real) or 1 (fake)", + HFILL } + }, + { &hf_cmpp_deliver_Registered_Delivery, + { "Deliver Report", "cmpp.deliver.Registered_Delivery", + FT_BOOLEAN, BASE_DEC, NULL, 0x00, + "The message is a deliver report if this value = 1", + HFILL } + }, + { &hf_cmpp_deliver_Report, + { "Detail Deliver Report", "cmpp.deliver.Report", + FT_NONE, BASE_NONE, NULL, 0x00, + "The detail report", + HFILL } + }, + { &hf_cmpp_deliver_Report_Stat, + { "Deliver Status", "cmpp.deliver.Report.Status", + FT_STRING, BASE_NONE, NULL, 0x00, + "Deliver Status", + HFILL } + }, + { &hf_cmpp_deliver_Report_Submit_time, + { "Submit_time", "cmpp.deliver.Report.Submit_time", + FT_STRING, BASE_NONE, NULL, 0x00, + "Format YYMMDDHHMM", + HFILL } + }, + { &hf_cmpp_deliver_Report_Done_time, + { "Done_time", "cmpp.deliver.Report.Done_time", + FT_STRING, BASE_NONE, NULL, 0x00, + "Format YYMMDDHHMM", + HFILL } + }, + { &hf_cmpp_deliver_Report_SMSC_sequence, + { "SMSC_sequence", "cmpp.Report.SMSC_sequence", + FT_UINT32, BASE_DEC, NULL, 0x00, + "Sequence number", + HFILL } + }, + { &hf_cmpp_deliver_resp_Result, + { "Result", "cmpp.deliver_resp.Result", + FT_UINT32, BASE_DEC, VALS(vals_Deliver_Resp_Result), 0x00, + "Deliver Result", + HFILL } + } + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_cmpp, + &ett_msg_id, + &ett_deliver_report, + }; + + /* Register the protocol name and description */ + proto_cmpp = proto_register_protocol("China Mobile Point to Point Protocol", + "CMPP", "cmpp"); + + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_cmpp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + +} + + +void +proto_reg_handoff_cmpp(void) +{ + static gboolean inited = FALSE; + + if (!inited) + { + dissector_handle_t cmpp_handle; + + cmpp_handle = new_create_dissector_handle(dissect_cmpp, proto_cmpp); + dissector_add("tcp.port", CMPP_SP_LONG_PORT, cmpp_handle); + dissector_add("tcp.port", CMPP_SP_SHORT_PORT, cmpp_handle); + dissector_add("tcp.port", CMPP_ISMG_LONG_PORT, cmpp_handle); + dissector_add("tcp.port", CMPP_ISMG_SHORT_PORT, cmpp_handle); + + inited = TRUE; + } +} |