diff options
Diffstat (limited to 'epan/dissectors/packet-cimd.c')
-rw-r--r-- | epan/dissectors/packet-cimd.c | 1103 |
1 files changed, 1103 insertions, 0 deletions
diff --git a/epan/dissectors/packet-cimd.c b/epan/dissectors/packet-cimd.c new file mode 100644 index 00000000..6ef145f8 --- /dev/null +++ b/epan/dissectors/packet-cimd.c @@ -0,0 +1,1103 @@ +/* packet-cimd.c + * + * Routines for Computer Interface to Message Distribution (CIMD) version 2 dissection + * + * Copyright : 2005 Viorel Suman <vsuman[AT]avmob.ro>, Lucian Piros <lpiros[AT]avmob.ro> + * In association with Avalanche Mobile BV, http://www.avmob.com + * + * Updates : + * Sub routines for further dissection of Status and Error codes added by Vineeth <vineethvijaysv@gmail.com> + * + * Refer to the AUTHORS file or the AUTHORS section in the man page + * for contacting the author(s) of this file. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "config.h" + +#include <stdlib.h> + +#include <epan/packet.h> +#include <epan/charsets.h> +#define CIMD_STX 0x02 /* Start of CIMD PDU */ +#define CIMD_ETX 0x03 /* End of CIMD PDU */ +#define CIMD_COLON 0x3A /* CIMD colon */ +#define CIMD_DELIM 0x09 /* CIMD Delimiter */ + +#define CIMD_OC_OFFSET 1 /* CIMD Operation Code Offset */ +#define CIMD_OC_LENGTH 2 /* CIMD Operation Code Length */ +#define CIMD_PN_OFFSET 4 /* CIMD Packet Number Offset */ +#define CIMD_PN_LENGTH 3 /* CIMD Packet Number Length */ +#define CIMD_PC_LENGTH 3 /* CIMD Parameter Code Length */ +#define CIMD_MIN_LENGTH 9 /* CIMD Minimal packet length : STX(1) + OC(2) + COLON(1) + PN(3) + DELIM(1) + ETX(1)*/ + +/* define CIMD2 operation code */ + +#define CIMD_Login 1 +#define CIMD_LoginResp 51 +#define CIMD_Logout 2 +#define CIMD_LogoutResp 52 +#define CIMD_SubmitMessage 3 +#define CIMD_SubmitMessageResp 53 +#define CIMD_EnqMessageStatus 4 +#define CIMD_EnqMessageStatusResp 54 +#define CIMD_DeliveryRequest 5 +#define CIMD_DeliveryRequestResp 55 +#define CIMD_CancelMessage 6 +#define CIMD_CancelMessageResp 56 +#define CIMD_SetMessage 8 +#define CIMD_SetMessageResp 58 +#define CIMD_GetMessage 9 +#define CIMD_GetMessageResp 59 +#define CIMD_Alive 40 +#define CIMD_AliveResp 90 +#define CIMD_GeneralErrorResp 98 +#define CIMD_NACK 99 + /* SC2App */ +#define CIMD_DeliveryMessage 20 +#define CIMD_DeliveryMessageResp 70 +#define CIMD_DeliveryStatusReport 23 +#define CIMD_DeliveryStatusReportResp 73 + +/* define CIMD2 operation's parameter codes */ + +#define CIMD_UserIdentity 10 +#define CIMD_Password 11 +#define CIMD_Subaddress 12 +#define CIMD_WindowSize 19 +#define CIMD_DestinationAddress 21 +#define CIMD_OriginatingAddress 23 +#define CIMD_OriginatingImsi 26 +#define CIMD_AlphaOriginatingAddr 27 +#define CIMD_OriginatedVisitedMSCAd 28 +#define CIMD_DataCodingScheme 30 +#define CIMD_UserDataHeader 32 +#define CIMD_UserData 33 +#define CIMD_UserDataBinary 34 +#define CIMD_MoreMessagesToSend 44 +#define CIMD_ValidityPeriodRelative 50 +#define CIMD_ValidityPeriodAbsolute 51 +#define CIMD_ProtocolIdentifier 52 +#define CIMD_FirstDeliveryTimeRel 53 +#define CIMD_FirstDeliveryTimeAbs 54 +#define CIMD_ReplyPath 55 +#define CIMD_StatusReportRequest 56 +#define CIMD_CancelEnabled 58 +#define CIMD_CancelMode 59 +#define CIMD_SCTimeStamp 60 +#define CIMD_StatusCode 61 +#define CIMD_StatusErrorCode 62 +#define CIMD_DischargeTime 63 +#define CIMD_TariffClass 64 +#define CIMD_ServiceDescription 65 +#define CIMD_MessageCount 66 +#define CIMD_Priority 67 +#define CIMD_DeliveryRequestMode 68 +#define CIMD_SCAddress 69 +#define CIMD_GetParameter 500 +#define CIMD_SMSCTime 501 +#define CIMD_ErrorCode 900 +#define CIMD_ErrorText 901 + +#define MAXPARAMSCOUNT 37 + +typedef struct cimd_parameter_t cimd_parameter_t; + +typedef void (*cimd_pdissect)(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset); + +struct cimd_parameter_t { + cimd_pdissect diss; + gint *ett_p; + gint *hf_p; +}; + +void proto_register_cimd(void); +void proto_reg_handoff_cimd(void); +static void dissect_cimd_parameter(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset); +static void dissect_cimd_ud(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset); +static void dissect_cimd_dcs(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset); +static void dissect_cimd_error_code(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset); + +static dissector_handle_t cimd_handle; + +static int proto_cimd = -1; +/* Initialize the subtree pointers */ +static gint ett_cimd = -1; + +/* Initialize the protocol and registered fields */ +static int hf_cimd_opcode_indicator = -1; +static int hf_cimd_packet_number_indicator = -1; +static int hf_cimd_checksum_indicator = -1; +static int hf_cimd_pcode_indicator = -1; + +static int hf_cimd_dcs_coding_group_indicatorC0 = -1; +static int hf_cimd_dcs_coding_group_indicatorF0 = -1; +static int hf_cimd_dcs_compressed_indicator = -1; +static int hf_cimd_dcs_message_class_meaning_indicator = -1; +static int hf_cimd_dcs_message_class_indicator = -1; +static int hf_cimd_dcs_character_set_indicator0C = -1; +static int hf_cimd_dcs_character_set_indicator04 = -1; +static int hf_cimd_dcs_indication_sense = -1; +static int hf_cimd_dcs_indication_type = -1; + +static const value_string vals_hdr_OC[] = { + /* operation codes array */ + {CIMD_Login, "Login"}, + {CIMD_LoginResp, "Login Resp"}, + {CIMD_Logout, "Logout"}, + {CIMD_LogoutResp, "Logout Resp"}, + {CIMD_SubmitMessage, "Submit message"}, + {CIMD_SubmitMessageResp, "Submit message Resp"}, + {CIMD_EnqMessageStatus, "Enquire message status"}, + {CIMD_EnqMessageStatusResp, "Enquire message status Resp"}, + {CIMD_DeliveryRequest, "Delivery request"}, + {CIMD_DeliveryRequestResp, "Delivery request Resp"}, + {CIMD_CancelMessage, "Cancel message"}, + {CIMD_CancelMessageResp, "Cancel message Resp"}, + {CIMD_SetMessage, "Set message"}, + {CIMD_SetMessageResp, "Set message Resp"}, + {CIMD_GetMessage, "Get message"}, + {CIMD_GetMessageResp, "Get message Resp"}, + {CIMD_Alive, "Alive"}, + {CIMD_AliveResp, "Alive Resp"}, + {CIMD_GeneralErrorResp, "General error Resp"}, + {CIMD_NACK, "Nack"}, + /* SC2App */ + {CIMD_DeliveryMessage, "Deliver message"}, + {CIMD_DeliveryMessageResp, "Deliver message Resp"}, + {CIMD_DeliveryStatusReport, "Deliver status report"}, + {CIMD_DeliveryStatusReportResp, "Deliver status report Resp"}, + {0, NULL} +}; + +static const value_string cimd_vals_PC[] = { + /* parameter codes array */ + {CIMD_UserIdentity, "User Identity"}, + {CIMD_Password, "Password"}, + {CIMD_Subaddress, "Subaddr"}, + {CIMD_WindowSize, "Window Size"}, + {CIMD_DestinationAddress, "Destination Address"}, + {CIMD_OriginatingAddress, "Originating Address"}, + {CIMD_OriginatingImsi, "Originating IMSI"}, + {CIMD_AlphaOriginatingAddr, "Alphanumeric Originating Address"}, + {CIMD_OriginatedVisitedMSCAd, "Originated Visited MSC Address"}, + {CIMD_DataCodingScheme, "Data Coding Scheme"}, + {CIMD_UserDataHeader, "User Data Header"}, + {CIMD_UserData, "User Data"}, + {CIMD_UserDataBinary, "User Data Binary"}, + {CIMD_MoreMessagesToSend, "More Messages To Send"}, + {CIMD_ValidityPeriodRelative, "Validity Period Relative"}, + {CIMD_ValidityPeriodAbsolute, "Validity Period Absolute"}, + {CIMD_ProtocolIdentifier, "Protocol Identifier"}, + {CIMD_FirstDeliveryTimeRel, "First Delivery Time Relative"}, + {CIMD_FirstDeliveryTimeAbs, "First Delivery Time Absolute"}, + {CIMD_ReplyPath, "Reply Path"}, + {CIMD_StatusReportRequest, "Status Report Request"}, + {CIMD_CancelEnabled, "Cancel Enabled"}, + {CIMD_CancelMode, "Cancel Mode"}, + {CIMD_SCTimeStamp, "Service Centre Time Stamp"}, + {CIMD_StatusCode, "Status Code"}, + {CIMD_StatusErrorCode, "Status Error Code"}, + {CIMD_DischargeTime, "Discharge Time"}, + {CIMD_TariffClass, "Tariff Class"}, + {CIMD_ServiceDescription, "Service Description"}, + {CIMD_MessageCount, "Message Count"}, + {CIMD_Priority, "Priority"}, + {CIMD_DeliveryRequestMode, "Delivery Request Mode"}, + {CIMD_SCAddress, "Service Center Address"}, + {CIMD_GetParameter, "Get Parameter"}, + {CIMD_SMSCTime, "SMS Center Time"}, + {CIMD_ErrorCode, "Error Code"}, + {CIMD_ErrorText, "Error Text"}, + {0, NULL} +}; + +static const value_string cimd_dcs_coding_groups[] = { + {0x00, "General Data Coding indication"}, + {0x01, "General Data Coding indication"}, + {0x02, "General Data Coding indication"}, + {0x03, "General Data Coding indication"}, + {0x04, "Message Marked for Automatic Deletion Group"}, + {0x05, "Message Marked for Automatic Deletion Group"}, + {0x06, "Message Marked for Automatic Deletion Group"}, + {0x07, "Message Marked for Automatic Deletion Group"}, + {0x08, "Reserved coding group"}, + {0x09, "Reserved coding group"}, + {0x0A, "Reserved coding group"}, + {0x0B, "Reserved coding group"}, + {0x0C, "Message Waiting Indication Group: Discard Message (7-bit encoded)"}, + {0x0D, "Message Waiting Indication Group: Store Message (7-bit encoded)"}, + {0x0E, "Message Waiting Indication Group: Store Message (uncompressed UCS2 encoded)"}, + {0x0F, "Data coding/message class"}, + {0, NULL} +}; + +static const value_string cimd_dcs_compressed[] = { + {0x00, "Text is uncompressed"}, + {0x01, "Text is compressed"}, + {0, NULL} +}; + +static const value_string cimd_dcs_message_class_meaning[] = { + {0x00, "Reserved, bits 1 to 0 have no message class meaning"}, + {0x01, "Bits 1 to 0 have message class meaning"}, + {0, NULL} +}; + +static const value_string cimd_dcs_message_class[] = { + {0x00, "Class 0"}, + {0x01, "Class 1 Default meaning: ME-specific"}, + {0x02, "Class 2 (U)SIM specific message"}, + {0x03, "Class 3 Default meaning: TE-specific"}, + {0, NULL} +}; + +static const value_string cimd_dcs_character_set[] = { + {0x00, "GSM 7 bit default alphabet"}, + {0x01, "8 bit data"}, + {0x02, "UCS2 (16bit)"}, + {0x03, "Reserved"}, + {0, NULL} +}; + +static const value_string cimd_dcs_indication_sense[] = { + {0x00, "Set Indication Inactive"}, + {0x01, "Set Indication Active"}, + {0, NULL} +}; + +static const value_string cimd_dcs_indication_type[] = { + {0x00, "Voicemail Message Waiting"}, + {0x01, "Fax Message Waiting"}, + {0x02, "Electronic Mail Message Waiting"}, + {0x03, "Other Message Waiting"}, + {0, NULL} +}; + +static const value_string cimd_error_vals[] = { + {1, "Unexpected operation"}, + {2, "Syntax error"}, + {3, "Unsupported parameter error"}, + {4, "Connection to SMS Center lost"}, + {5, "No response from SMS Center"}, + {6, "General system error"}, + {7, "Cannot find information"}, + {8, "Parameter formatting error"}, + {9, "Requested operation failed"}, + {10, "Temporary congestion error"}, + {100, "Invalid login"}, + {101, "Incorrect access type"}, + {102, "Too many users with this login ID"}, + {103, "Login refused by SMS Center"}, + {104, "Invalid window size"}, + {105, "Windowing disabled"}, + {106, "Virtual SMS Center-based barring"}, + {107, "Invalid subaddr"}, + {108, "Alias account, login refused"}, + {300, "Incorrect destination address"}, + {301, "Incorrect number of destination addresses"}, + {302, "Syntax error in user data parameter"}, + {303, "Incorrect bin/head/normal user data parameter combination"}, + {304, "Incorrect dcs parameter usage"}, + {305, "Incorrect validity period parameters usage"}, + {306, "Incorrect originator address usage"}, + {307, "Incorrect PID parameter usage"}, + {308, "Incorrect first delivery parameter usage"}, + {309, "Incorrect reply path usage"}, + {310, "Incorrect status report request parameter usage"}, + {311, "Incorrect cancel enabled parameter usage"}, + {312, "Incorrect priority parameter usage"}, + {313, "Incorrect tariff class parameter usage"}, + {314, "Incorrect service description parameter usage"}, + {315, "Incorrect transport type parameter usage"}, + {316, "Incorrect message type parameter usage"}, + {318, "Incorrect MMs parameter usage"}, + {319, "Incorrect operation timer parameter usage"}, + {320, "Incorrect dialogue ID parameter usage"}, + {321, "Incorrect alpha originator address usage"}, + {322, "Invalid data for alpha numeric originator"}, + {400, "Incorrect address parameter usage"}, + {401, "Incorrect scts parameter usage"}, + {500, "Incorrect scts parameter usage"}, + {501, "Incorrect mode parameter usage"}, + {502, "Incorrect parameter combination"}, + {600, "Incorrect scts parameter usage"}, + {601, "Incorrect address parameter usage"}, + {602, "Incorrect mode parameter usage"}, + {603, "Incorrect parameter combination"}, + {800, "Changing password failed"}, + {801, "Changing password not allowed"}, + {900, "Unsupported item requested"}, + {0, NULL} +}; + +static value_string_ext cimd_error_vals_ext = VALUE_STRING_EXT_INIT(cimd_error_vals); + +static const value_string cimd_status_code_vals[] = { + {1, " in process"}, + {2, " validity period expired"}, + {3, " delivery failed"}, + {4, " delivery successful"}, + {5, " no response"}, + {6, " last no response"}, + {7, " message cancelled"}, + {8, " message deleted"}, + {9, " message deleted by cancel"}, + {0, NULL} +}; + +static const value_string cimd_status_error_vals[] = { + {1, "Unknown subscriber"}, + {9, "Illegal subscriber"}, + {11, "Teleservice not provisioned"}, + {13, "Call barred"}, + {15, "CUG reject"}, + {19, "No SMS support in MS"}, + {20, "Error in MS"}, + {21, "Facility not supported"}, + {22, "Memory capacity exceeded"}, + {29, "Absent subscriber"}, + {30, "MS busy for MT SMS"}, + {36, "Network/Protocol failure"}, + {44, "Illegal equipment"}, + {60, "No paging response"}, + {61, "GMSC congestion"}, + {63, "HLR timeout"}, + {64, "MSC/SGSN_timeout"}, + {70, "SMRSE/TCP error"}, + {72, "MT congestion"}, + {75, "GPRS suspended"}, + {80, "No paging response via MSC"}, + {81, "IMSI detached"}, + {82, "Roaming restriction"}, + {83, "Deregistered in HLR for GSM"}, + {84, "Purged for GSM"}, + {85, "No paging response via SGSN"}, + {86, "GPRS detached"}, + {87, "Deregistered in HLR for GPRS"}, + {88, "The MS purged for GPRS"}, + {89, "Unidentified subscriber via MSC"}, + {90, "Unidentified subscriber via SGSN"}, + {112, "Originator missing credit on prepaid account"}, + {113, "Destination missing credit on prepaid account"}, + {114, "Error in prepaid system"}, + {0, NULL} +}; + +static value_string_ext cimd_status_error_vals_ext = VALUE_STRING_EXT_INIT(cimd_status_error_vals); + +static const cimd_pdissect cimd_pc_handles[] = { + /* function handles for parsing cimd parameters */ + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_dcs, + dissect_cimd_parameter, + dissect_cimd_ud, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_error_code, + dissect_cimd_error_code, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_parameter, + dissect_cimd_error_code, + dissect_cimd_parameter +}; + +/* Parameters */ +static cimd_parameter_t vals_hdr_PC[MAXPARAMSCOUNT + 1]; +static gint ett_index[MAXPARAMSCOUNT]; +static gint hf_index[MAXPARAMSCOUNT]; + +static void dissect_cimd_parameter(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset) +{ + /* Set up structures needed to add the param subtree and manage it */ + proto_tree *param_tree; + + param_tree = proto_tree_add_subtree(tree, tvb, startOffset + 1, endOffset - (startOffset + 1), + (*vals_hdr_PC[pindex].ett_p), NULL, cimd_vals_PC[pindex].strptr); + + proto_tree_add_item(param_tree, hf_cimd_pcode_indicator, tvb, + startOffset + 1, CIMD_PC_LENGTH, ENC_ASCII); + proto_tree_add_item(param_tree, (*vals_hdr_PC[pindex].hf_p), tvb, + startOffset + 1 + CIMD_PC_LENGTH + 1, endOffset - (startOffset + 1 + CIMD_PC_LENGTH + 1), ENC_ASCII|ENC_NA); +} + +static void dissect_cimd_ud(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset) +{ + /* Set up structures needed to add the param subtree and manage it */ + proto_tree *param_tree; + + guint8 *tmpBuffer1; + const guint8* payloadText; + wmem_strbuf_t *tmpBuffer; + int loop; + gint g_offset, g_size; + gchar token[4]; + + /* The user data (33) parameter is used when the data coding scheme (30) + * indicates that the default GSM character set is being used. + * It is not transmitted directly as the 23.038 GSM encoding (packed + * or unpacked), but rather each character is converted to ASCII + * or Latin-1 (ISO-8859-1). + * + * (XXX: It is possible that the UDH indicates that a national + * language shift table is to be used, but we don't implement that. + * It is also theoretically possible for some encoding other than + * Latin-1 to be used.) + * + * It is simplest to first convert back to the GSM 7 bit encoding (unpacked), + * and then convert that to UTF-8, since the GSM extension table characters + * require a second level of escape handling. We will use '\xff' as a + * placeholder for illegal characters that will be replaced with Unicode + * REPLACEMENT CHARACTERS upon final conversion. + */ + static const value_string combining_mapping[] = { + { 0, "_Oa"}, + { 1, "_L-"}, + { 3, "_Y-"}, + { 4, "_e`"}, + { 5, "_e'"}, + { 6, "_u`"}, + { 7, "_i`"}, + { 8, "_o`"}, + { 9, "_C,"}, + { 11, "_O/"}, + { 12, "_o/"}, + { 14, "_A*"}, + { 15, "_a*"}, + { 16, "_gd"}, + { 17, "_--"}, + { 18, "_gf"}, + { 19, "_gg"}, + { 20, "_gl"}, + { 21, "_go"}, + { 22, "_gp"}, + { 23, "_gi"}, + { 24, "_gs"}, + { 25, "_gt"}, + { 26, "_gx"}, + { 27, "_XX"}, + { 28, "_AE"}, + { 29, "_ae"}, + { 30, "_ss"}, + { 31, "_E'"}, + { 34, "_qq"}, + { 36, "_ox"}, + { 40, "_!!"}, + { 91, "_A\""}, + { 92, "_O\""}, + { 93, "_N~"}, + { 94, "_U\""}, + { 95, "_so"}, + { 96, "_??"}, + {123, "_a\""}, + {124, "_o\""}, + {125, "_n~"}, + {126, "_n\""}, + {127, "_a`"}, + { 0, NULL } + }; + + static const char latin_mapping[256] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00 - */ + 0xff, 0xff, 0x0a, 0xff, 0xff, 0x0d, 0xff, 0xff, /* - 0x0F */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10 - */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* - 0x1F */ + 0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, /* 0x20 - */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* - 0x2F */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 - */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* - 0x3F */ + 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 - */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* - 0x4F */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 - */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x0e, 0x5e, 0xff, /* - 0x5F */ + 0xff, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 - */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* - 0x6F */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 - */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x0f, 0x7e, 0xff, /* - 0x7F */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80 - */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* - 0x8F */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 - */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* - 0x9F */ + 0xff, 0x40, 0xff, 0x01, 0x24, 0x03, 0xff, 0x5f, /* 0xA0 - */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* - 0xAF */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xB0 - */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60, /* - 0xBF */ + 0xff, 0xff, 0xff, 0xff, 0x5b, 0x0e, 0x1c, 0x09, /* 0xC0 - */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* - 0xCF */ + }; + + param_tree = proto_tree_add_subtree(tree, tvb, + startOffset + 1, endOffset - (startOffset + 1), + (*vals_hdr_PC[pindex].ett_p), NULL, cimd_vals_PC[pindex].strptr + ); + proto_tree_add_item(param_tree, hf_cimd_pcode_indicator, tvb, + startOffset + 1, CIMD_PC_LENGTH, ENC_ASCII); + + g_offset = startOffset + 1 + CIMD_PC_LENGTH + 1; + g_size = endOffset - g_offset; + + payloadText = tvb_get_ptr(tvb, g_offset, g_size); + tmpBuffer = wmem_strbuf_new_sized(wmem_packet_scope(), g_size+1); + for (loop = 0; loop < g_size; loop++) + { + if (payloadText[loop] == '_') + { + if (loop < g_size - 2) + { + token[0] = payloadText[loop++]; + token[1] = payloadText[loop++]; + token[2] = payloadText[loop]; + token[3] = '\0'; + wmem_strbuf_append_c(tmpBuffer, str_to_val(token, combining_mapping, 0xff)); + } + else + { + /* Not enough room for a combining sequence. */ + wmem_strbuf_append_c(tmpBuffer, 0xff); + } + } + else + { + wmem_strbuf_append_c(tmpBuffer, latin_mapping[payloadText[loop]]); + } + } + + tmpBuffer1 = get_ts_23_038_7bits_string_unpacked(wmem_packet_scope(), wmem_strbuf_get_str(tmpBuffer), (int)wmem_strbuf_get_len(tmpBuffer)); + wmem_strbuf_destroy(tmpBuffer); + proto_tree_add_string(param_tree, (*vals_hdr_PC[pindex].hf_p), tvb, g_offset, g_size, tmpBuffer1); +} + +static void dissect_cimd_dcs(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset) +{ + /* Set up structures needed to add the param subtree and manage it */ + proto_tree *param_tree; + gint offset; + guint32 dcs; + guint32 dcs_cg; /* coding group */ + + param_tree = proto_tree_add_subtree(tree, tvb, + startOffset + 1, endOffset - (startOffset + 1), + (*vals_hdr_PC[pindex].ett_p), NULL, cimd_vals_PC[pindex].strptr + ); + + proto_tree_add_item(param_tree, hf_cimd_pcode_indicator, tvb, + startOffset + 1, CIMD_PC_LENGTH, ENC_ASCII); + + offset = startOffset + 1 + CIMD_PC_LENGTH + 1; + dcs = (guint32) strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, offset, endOffset - offset, ENC_ASCII), NULL, 10); + proto_tree_add_uint(param_tree, (*vals_hdr_PC[pindex].hf_p), tvb, offset, endOffset - offset, dcs); + + dcs_cg = (dcs & 0xF0) >> 4; + if (dcs_cg <= 0x07) + { + proto_tree_add_uint(param_tree, hf_cimd_dcs_coding_group_indicatorC0, tvb, offset, 1, dcs); + } + else + { + proto_tree_add_uint(param_tree, hf_cimd_dcs_coding_group_indicatorF0, tvb, offset, 1, dcs); + } + + if (dcs_cg <= 0x07) + { + proto_tree_add_uint(param_tree, hf_cimd_dcs_compressed_indicator, tvb, offset, 1, dcs); + proto_tree_add_uint(param_tree, hf_cimd_dcs_message_class_meaning_indicator, tvb, offset, 1, dcs); + proto_tree_add_uint(param_tree, hf_cimd_dcs_character_set_indicator0C, tvb, offset, 1, dcs); + + if (dcs & 0x10) + { + proto_tree_add_uint(param_tree, hf_cimd_dcs_message_class_indicator, tvb, offset, 1, dcs); + } + } + else if (dcs_cg >= 0x0C && dcs_cg <= 0x0E) + { + proto_tree_add_uint(param_tree, hf_cimd_dcs_indication_sense, tvb, offset, 1, dcs); + proto_tree_add_uint(param_tree, hf_cimd_dcs_indication_type, tvb, offset, 1, dcs); + } + else if (dcs_cg == 0x0F) + { + proto_tree_add_uint(param_tree, hf_cimd_dcs_character_set_indicator04, tvb, offset, 1, dcs); + proto_tree_add_uint(param_tree, hf_cimd_dcs_message_class_indicator, tvb, offset, 1, dcs); + } +} + +static void dissect_cimd_error_code( tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset ) +{ + /* Same routine can be used to dissect CIMD Error,Status and Status Error Codes */ + proto_tree *param_tree; + guint32 err_code; + + param_tree = proto_tree_add_subtree(tree, tvb, startOffset + 1, endOffset - (startOffset + 1), + (*vals_hdr_PC[pindex].ett_p), NULL, cimd_vals_PC[pindex].strptr); + + proto_tree_add_item(param_tree, hf_cimd_pcode_indicator, tvb, startOffset + 1, CIMD_PC_LENGTH, ENC_ASCII); + + err_code = (guint32) strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, + startOffset + 1 + CIMD_PC_LENGTH + 1, endOffset - (startOffset + 1 + CIMD_PC_LENGTH + 1), ENC_ASCII), + NULL, 10); + proto_tree_add_uint(param_tree, (*vals_hdr_PC[pindex].hf_p), tvb, startOffset + 1 + CIMD_PC_LENGTH + 1, endOffset - (startOffset + 1 + CIMD_PC_LENGTH + 1), err_code); +} + +static void +dissect_cimd_operation(tvbuff_t *tvb, proto_tree *tree, gint etxp, guint16 checksum, guint8 last1,guint8 OC, guint8 PN) +{ + guint32 PC = 0; /* Parameter code */ + gint idx; + gint offset = 0; + gint endOffset = 0; + proto_item *cimd_item; + proto_tree *cimd_tree; + + /* create display subtree for the protocol */ + cimd_item = proto_tree_add_item(tree, proto_cimd, tvb, 0, etxp + 1, ENC_NA); + cimd_tree = proto_item_add_subtree(cimd_item, ett_cimd); + proto_tree_add_uint(cimd_tree, hf_cimd_opcode_indicator, tvb, CIMD_OC_OFFSET, CIMD_OC_LENGTH, OC); + proto_tree_add_uint(cimd_tree, hf_cimd_packet_number_indicator, tvb, CIMD_PN_OFFSET, CIMD_PN_LENGTH, PN); + + offset = CIMD_PN_OFFSET + CIMD_PN_LENGTH; + while (offset < etxp && tvb_get_guint8(tvb, offset) == CIMD_DELIM) + { + endOffset = tvb_find_guint8(tvb, offset + 1, etxp, CIMD_DELIM); + if (endOffset == -1) + break; + + PC = (guint32) strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, offset + 1, CIMD_PC_LENGTH, ENC_ASCII), NULL, 10); + try_val_to_str_idx(PC, cimd_vals_PC, &idx); + if (idx != -1 && tree) + { + (vals_hdr_PC[idx].diss)(tvb, cimd_tree, idx, offset, endOffset); + } + offset = endOffset; + } + + if (last1 != CIMD_DELIM) + { + /* Checksum is present */ + proto_tree_add_uint(cimd_tree, hf_cimd_checksum_indicator, tvb, etxp - 2, 2, checksum); + } +} + +static int +dissect_cimd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + guint8 OC; /* Operation Code */ + guint8 PN; /* Packet number */ + guint16 checksum = 0; /* Checksum */ + guint16 pkt_check = 0; + gint etxp = 0; /* ETX position */ + gint offset = 0; + gboolean checksumIsValid = TRUE; + guint8 last1, last2, last3; + + etxp = tvb_find_guint8(tvb, CIMD_PN_OFFSET + CIMD_PN_LENGTH, -1, CIMD_ETX); + if (etxp == -1) return 0; + + OC = (guint8)strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, CIMD_OC_OFFSET, CIMD_OC_LENGTH, ENC_ASCII), NULL, 10); + PN = (guint8)strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, CIMD_PN_OFFSET, CIMD_PN_LENGTH, ENC_ASCII), NULL, 10); + + last1 = tvb_get_guint8(tvb, etxp - 1); + last2 = tvb_get_guint8(tvb, etxp - 2); + last3 = tvb_get_guint8(tvb, etxp - 3); + + if (last1 == CIMD_DELIM) { + /* valid packet, CC is missing */ + } else if (last1 != CIMD_DELIM && last2 != CIMD_DELIM && last3 == CIMD_DELIM) { + /* looks valid, it would be nice to check that last1 and last2 are HEXA */ + /* CC is present */ + checksum = (guint16)strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, etxp - 2, 2, ENC_ASCII), NULL, 16); + for (; offset < (etxp - 2); offset++) + { + pkt_check += tvb_get_guint8(tvb, offset); + pkt_check &= 0xFF; + } + checksumIsValid = (checksum == pkt_check); + } else { + checksumIsValid = FALSE; + } + + /* Make entries in Protocol column on summary display */ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIMD"); + + if (checksumIsValid) + col_add_str(pinfo->cinfo, COL_INFO, val_to_str(OC, vals_hdr_OC, "Unknown (%d)")); + else + col_add_fstr(pinfo->cinfo, COL_INFO, "%s - %s", val_to_str(OC, vals_hdr_OC, "Unknown (%d)"), "invalid checksum"); + + dissect_cimd_operation(tvb, tree, etxp, checksum, last1, OC, PN); + return tvb_captured_length(tvb); +} + +/** + * A 'heuristic dissector' that attemtps to establish whether we have + * a CIMD MSU here. + */ +static gboolean +dissect_cimd_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + int etxp; + guint8 opcode = 0; /* Operation code */ + + if (tvb_captured_length(tvb) < CIMD_MIN_LENGTH) + return FALSE; + + if (tvb_get_guint8(tvb, 0) != CIMD_STX) + return FALSE; + + etxp = tvb_find_guint8(tvb, CIMD_OC_OFFSET, -1, CIMD_ETX); + if (etxp == -1) + { /* XXX - should we have an option to request reassembly? */ + return FALSE; + } + + /* Try getting the operation-code */ + opcode = (guint8)strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, CIMD_OC_OFFSET, CIMD_OC_LENGTH, ENC_ASCII), NULL, 10); + if (try_val_to_str(opcode, vals_hdr_OC) == NULL) + return FALSE; + + if (tvb_get_guint8(tvb, CIMD_OC_OFFSET + CIMD_OC_LENGTH) != CIMD_COLON) + return FALSE; + + if (tvb_get_guint8(tvb, CIMD_PN_OFFSET + CIMD_PN_LENGTH) != CIMD_DELIM) + return FALSE; + + /* Ok, looks like a valid packet, go dissect. */ + dissect_cimd(tvb, pinfo, tree, data); + return TRUE; +} + +void +proto_register_cimd(void) +{ + static hf_register_info hf[] = { + { &hf_cimd_opcode_indicator, + { "Operation Code", "cimd.opcode", + FT_UINT8, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_cimd_packet_number_indicator, + { "Packet Number", "cimd.pnumber", + FT_UINT8, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_cimd_pcode_indicator, + { "Parameter Code", "cimd.pcode", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_cimd_checksum_indicator, + { "Checksum", "cimd.chksum", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_cimd_dcs_coding_group_indicatorC0, + { "DCS Coding Group", "cimd.dcs.cg", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_coding_groups), 0xC0, + NULL, HFILL } + }, + { &hf_cimd_dcs_coding_group_indicatorF0, + { "DCS Coding Group", "cimd.dcs.cg", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_coding_groups), 0xF0, + NULL, HFILL } + }, + { &hf_cimd_dcs_compressed_indicator, + { "DCS Compressed Flag", "cimd.dcs.cf", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_compressed), 0x20, + NULL, HFILL } + }, + { &hf_cimd_dcs_message_class_meaning_indicator, + { "DCS Message Class Meaning", "cimd.dcs.mcm", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_message_class_meaning), 0x10, + NULL, HFILL } + }, + { &hf_cimd_dcs_message_class_indicator, + { "DCS Message Class", "cimd.dcs.mc", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_message_class), 0x03, + NULL, HFILL } + }, + { &hf_cimd_dcs_character_set_indicator0C, + { "DCS Character Set", "cimd.dcs.chs", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_character_set), 0x0C, + NULL, HFILL } + }, + { &hf_cimd_dcs_character_set_indicator04, + { "DCS Character Set", "cimd.dcs.chs", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_character_set), 0x04, + NULL, HFILL } + }, + { &hf_cimd_dcs_indication_sense, + { "DCS Indication Sense", "cimd.dcs.is", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_indication_sense), 0x04, + NULL, HFILL } + }, + { &hf_cimd_dcs_indication_type, + { "DCS Indication Type", "cimd.dcs.it", + FT_UINT8, BASE_DEC, VALS(cimd_dcs_indication_type), 0x03, + NULL, HFILL } + }, + { &hf_index[0], + { "User Identity", "cimd.ui", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[1], + { "Password", "cimd.passwd", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[2], + { "Subaddress", "cimd.saddr", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[3], + { "Window Size", "cimd.ws", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[4], + { "Destination Address", "cimd.da", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[5], + { "Originating Address", "cimd.oa", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[6], + { "Originating IMSI", "cimd.oimsi", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[7], + { "Alphanumeric Originating Address", "cimd.aoi", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[8], + { "Originated Visited MSC Address", "cimd.ovma", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[9], + { "Data Coding Scheme", "cimd.dcs", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[10], + { "User Data Header", "cimd.udh", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[11], + { "User Data", "cimd.ud", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[12], + { "User Data Binary", "cimd.udb", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[13], + { "More Messages To Send", "cimd.mms", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[14], + { "Validity Period Relative", "cimd.vpr", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[15], + { "Validity Period Absolute", "cimd.vpa", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[16], + { "Protocol Identifier", "cimd.pi", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[17], + { "First Delivery Time Relative", "cimd.fdtr", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[18], + { "First Delivery Time Absolute", "cimd.fdta", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[19], + { "Reply Path", "cimd.rpath", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[20], + { "Status Report Request", "cimd.srr", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[21], + { "Cancel Enabled", "cimd.ce", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[22], + { "Cancel Mode", "cimd.cm", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[23], + { "Service Center Time Stamp", "cimd.scts", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[24], + { "Status Code", "cimd.stcode", + FT_UINT8, BASE_DEC, VALS(cimd_status_code_vals), 0x00, + NULL, HFILL } + }, + { &hf_index[25], + { "Status Error Code", "cimd.sterrcode", + FT_UINT16, BASE_DEC|BASE_EXT_STRING, &cimd_status_error_vals_ext, 0x00, + NULL, HFILL } + }, + { &hf_index[26], + { "Discharge Time", "cimd.dt", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[27], + { "Tariff Class", "cimd.tclass", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[28], + { "Service Description", "cimd.sdes", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[29], + { "Message Count", "cimd.mcount", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[30], + { "Priority", "cimd.priority", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[31], + { "Delivery Request Mode", "cimd.drmode", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[32], + { "Service Center Address", "cimd.scaddr", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[33], + { "Get Parameter", "cimd.gpar", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[34], + { "SMS Center Time", "cimd.smsct", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_index[35], + { "Error Code Description", "cimd.errcode", + FT_UINT16, BASE_DEC|BASE_EXT_STRING, &cimd_error_vals_ext, 0x00, + NULL, HFILL } + }, + { &hf_index[36], + { "Error Text", "cimd.errtext", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + } + }; + + /* Setup protocol subtree array */ + gint *ett[MAXPARAMSCOUNT + 1]; + int i; + + ett[0] = &ett_cimd; + + for(i=0;i<MAXPARAMSCOUNT;i++) + { + ett_index[i] = -1; + ett[i + 1] = &(ett_index[i]); + vals_hdr_PC[i].ett_p = &(ett_index[i]); + vals_hdr_PC[i].hf_p = &(hf_index[i]); + vals_hdr_PC[i].diss = cimd_pc_handles[i]; + }; + + /* Register the protocol name and description */ + proto_cimd = proto_register_protocol("Computer Interface to Message Distribution", "CIMD", "cimd"); + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_cimd, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + /* Register the dissector */ + cimd_handle = register_dissector("cimd", dissect_cimd, proto_cimd); +} + +void +proto_reg_handoff_cimd(void) +{ + /** + * CIMD can be spoken on any port so, when not on a specific port, try this + * one whenever TCP is spoken. + */ + heur_dissector_add("tcp", dissect_cimd_heur, "CIMD over TCP", "cimd_tcp", proto_cimd, HEURISTIC_ENABLE); + + /** + * Also register as one that can be selected by a TCP port number. + */ + dissector_add_for_decode_as_with_preference("tcp.port", cimd_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local Variables: + * c-basic-offset: 2 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */ |