/* packet-cmpp.c * Routines for China Mobile Point to Point dissection * Copyright 2007, Andy Chu * * Wireshark - Network traffic analyzer * By Gerald Combs * 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. */ #include "config.h" #include #include "packet-tcp.h" #define CMPP_FIX_HEADER_LENGTH 12 #define CMPP_DELIVER_REPORT_LEN 71 /* These are not registered with IANA */ #define CMPP_PORT_RANGE "7890,7900,7930,9168" void proto_register_cmpp(void); 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 const guint8* cmpp_octet_string(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset, gint length) { const guint8 *display; proto_tree_add_item_ret_string(tree, field, tvb, offset, length, ENC_ASCII, wmem_packet_scope(), &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 = wmem_strdup_printf(wmem_packet_scope(), "%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 = wmem_strdup_printf(wmem_packet_scope(), "%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 *pi; proto_tree *sub_tree; char *strval; pi = proto_tree_add_item(tree, field, tvb, offset, 8, ENC_BIG_ENDIAN); sub_tree = proto_item_add_subtree(pi, 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 = wmem_strdup_printf(wmem_packet_scope(), "%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 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++; 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 *pi; proto_tree *sub_tree; pi = proto_tree_add_item(tree, field, tvb, offset, CMPP_DELIVER_REPORT_LEN, ENC_BIG_ENDIAN); sub_tree = proto_item_add_subtree(pi, 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 int dissect_cmpp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { /* 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_captured_length(tvb); /* if the length of the tvb is shorder then the cmpp header length exit */ if (tvb_len < CMPP_FIX_HEADER_LENGTH) return 0; total_length = tvb_get_ntohl(tvb, 0); /* Get the pdu length */ command_id = tvb_get_ntohl(tvb, 4); /* get the pdu command id */ if (try_val_to_str(command_id, vals_command_Id) == NULL) { /* Should never happen: we checked this in dissect_cmpp() */ return 0; } 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) { /* Should never happen: TCP should have desegmented for us */ return 0; } /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "CMPP"); col_append_fstr(pinfo->cinfo, COL_INFO, "%s. ", command_str); if (tree) { ti = proto_tree_add_item(tree, proto_cmpp, tvb, 0, -1, ENC_NA); 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; } } return tvb_reported_length(tvb); } /* Get the CMPP PDU Length */ static guint get_cmpp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) { return tvb_get_ntohl(tvb, offset); } static int dissect_cmpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { guint total_length, command_id, tvb_len; /* Check that there's enough data */ tvb_len = tvb_captured_length(tvb); if (tvb_len < 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 */ /* Looking at this protocol, it seems unlikely that the messages would * get as big as a couple hundred bytes but that's not certain; just * added a hopefully-way-too-big number to strengthen the heuristics. */ if (total_length < CMPP_FIX_HEADER_LENGTH || total_length > 1000) return 0; if (try_val_to_str(command_id, vals_command_Id) == NULL) return 0; 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, data); /* Return the amount of data this dissector was able to dissect */ return tvb_reported_length(tvb); } /* Register the protocol with Wireshark */ 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_NONE, NULL, 0x0, "Registered Delivery flag", HFILL } }, { &hf_cmpp_submit_Msg_level, { "Message Level", "cmpp.submit.Msg_level", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, 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_NONE, NULL, 0x0, "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, NULL, 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, NULL, HFILL } }, { &hf_cmpp_submit_FeeCode, { "Fee Code", "cmpp.submit.FeeCode", FT_STRING, BASE_NONE, NULL, 0x00, NULL, 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_NONE, NULL, 0x0, "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, NULL, HFILL } }, { &hf_cmpp_LinkID, { "Link ID", "cmpp.LinkID", FT_STRING, BASE_NONE, NULL, 0x00, NULL, 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_NONE, NULL, 0x0, "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_NONE, NULL, 0x0, "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, NULL, 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) { dissector_handle_t cmpp_handle; cmpp_handle = create_dissector_handle(dissect_cmpp, proto_cmpp); dissector_add_uint_range_with_preference("tcp.port", CMPP_PORT_RANGE, cmpp_handle); } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: * * vi: set shiftwidth=8 tabstop=8 noexpandtab: * :indentSize=8:tabSize=8:noTabs=false: */