diff options
Diffstat (limited to 'epan/dissectors/packet-ucp.c')
-rw-r--r-- | epan/dissectors/packet-ucp.c | 420 |
1 files changed, 246 insertions, 174 deletions
diff --git a/epan/dissectors/packet-ucp.c b/epan/dissectors/packet-ucp.c index 53020f8cdc..c93b3fa1b7 100644 --- a/epan/dissectors/packet-ucp.c +++ b/epan/dissectors/packet-ucp.c @@ -28,6 +28,7 @@ #include <epan/prefs.h> #include <epan/expert.h> #include <epan/stats_tree.h> +#include <epan/charsets.h> #include <wsutil/strtoi.h> @@ -79,12 +80,12 @@ static dissector_handle_t ucp_handle; * * Header (fixed) section */ -static int proto_ucp = -1; +static int proto_ucp; -static int hf_ucp_hdr_TRN = -1; -static int hf_ucp_hdr_LEN = -1; -static int hf_ucp_hdr_O_R = -1; -static int hf_ucp_hdr_OT = -1; +static int hf_ucp_hdr_TRN; +static int hf_ucp_hdr_LEN; +static int hf_ucp_hdr_O_R; +static int hf_ucp_hdr_OT; /* * Stats section @@ -106,124 +107,126 @@ static const gchar st_str_neg[] = "Negative"; /* * Data (variable) section */ -static int hf_ucp_oper_section = -1; -static int hf_ucp_parm_AdC = -1; -static int hf_ucp_parm_OAdC = -1; -static int hf_ucp_parm_DAdC = -1; -static int hf_ucp_parm_AC = -1; -static int hf_ucp_parm_OAC = -1; -static int hf_ucp_parm_BAS = -1; -static int hf_ucp_parm_LAR = -1; -static int hf_ucp_parm_LAC = -1; -static int hf_ucp_parm_L1R = -1; -static int hf_ucp_parm_L1P = -1; -static int hf_ucp_parm_L3R = -1; -static int hf_ucp_parm_L3P = -1; -static int hf_ucp_parm_LCR = -1; -static int hf_ucp_parm_LUR = -1; -static int hf_ucp_parm_LRR = -1; -static int hf_ucp_parm_RT = -1; -static int hf_ucp_parm_NoN = -1; -static int hf_ucp_parm_NoA = -1; -static int hf_ucp_parm_NoB = -1; -static int hf_ucp_parm_NAC = -1; -static int hf_ucp_parm_PNC = -1; -static int hf_ucp_parm_AMsg = -1; -static int hf_ucp_parm_LNo = -1; -static int hf_ucp_parm_LST = -1; -static int hf_ucp_parm_TNo = -1; -static int hf_ucp_parm_CS = -1; -static int hf_ucp_parm_PID = -1; -static int hf_ucp_parm_NPL = -1; -static int hf_ucp_parm_GA = -1; -static int hf_ucp_parm_RP = -1; -static int hf_ucp_parm_LRP = -1; -static int hf_ucp_parm_PR = -1; -static int hf_ucp_parm_LPR = -1; -static int hf_ucp_parm_UM = -1; -static int hf_ucp_parm_LUM = -1; -static int hf_ucp_parm_RC = -1; -static int hf_ucp_parm_LRC = -1; -static int hf_ucp_parm_NRq = -1; -static int hf_ucp_parm_GAdC = -1; -static int hf_ucp_parm_A_D = -1; -static int hf_ucp_parm_CT = -1; -static int hf_ucp_parm_AAC = -1; -static int hf_ucp_parm_MNo = -1; -static int hf_ucp_parm_R_T = -1; -static int hf_ucp_parm_IVR5x = -1; -static int hf_ucp_parm_REQ_OT = -1; -static int hf_ucp_parm_SSTAT = -1; -static int hf_ucp_parm_LMN = -1; -static int hf_ucp_parm_NMESS = -1; -static int hf_ucp_parm_NAdC = -1; -static int hf_ucp_parm_NT = -1; -static int hf_ucp_parm_NPID = -1; -static int hf_ucp_parm_LRq = -1; -static int hf_ucp_parm_LRAd = -1; -static int hf_ucp_parm_LPID = -1; -static int hf_ucp_parm_DD = -1; -static int hf_ucp_parm_DDT = -1; -static int hf_ucp_parm_STx = -1; -static int hf_ucp_parm_ST = -1; -static int hf_ucp_parm_SP = -1; -static int hf_ucp_parm_VP = -1; -static int hf_ucp_parm_RPID = -1; -static int hf_ucp_parm_SCTS = -1; -static int hf_ucp_parm_Dst = -1; -static int hf_ucp_parm_Rsn = -1; -static int hf_ucp_parm_DSCTS = -1; -static int hf_ucp_parm_MT = -1; -static int hf_ucp_parm_NB = -1; -static int hf_ucp_data_section = -1; -static int hf_ucp_parm_MMS = -1; -static int hf_ucp_parm_DCs = -1; -static int hf_ucp_parm_MCLs = -1; -static int hf_ucp_parm_RPI = -1; -static int hf_ucp_parm_CPg = -1; -static int hf_ucp_parm_RPLy = -1; -static int hf_ucp_parm_OTOA = -1; -static int hf_ucp_parm_HPLMN = -1; -static int hf_ucp_parm_RES4 = -1; -static int hf_ucp_parm_RES5 = -1; -static int hf_ucp_parm_OTON = -1; -static int hf_ucp_parm_ONPI = -1; -static int hf_ucp_parm_STYP0 = -1; -static int hf_ucp_parm_STYP1 = -1; -static int hf_ucp_parm_ACK = -1; -static int hf_ucp_parm_PWD = -1; -static int hf_ucp_parm_NPWD = -1; -static int hf_ucp_parm_VERS = -1; -static int hf_ucp_parm_LAdC = -1; -static int hf_ucp_parm_LTON = -1; -static int hf_ucp_parm_LNPI = -1; -static int hf_ucp_parm_OPID = -1; -static int hf_ucp_parm_RES1 = -1; -static int hf_ucp_parm_RES2 = -1; -static int hf_ucp_parm_MVP = -1; -static int hf_ucp_parm_EC = -1; -static int hf_ucp_parm_SM = -1; -static int hf_ucp_not_subscribed = -1; -static int hf_ucp_ga_roaming = -1; -static int hf_ucp_call_barring = -1; -static int hf_ucp_deferred_delivery = -1; -static int hf_ucp_diversion = -1; - -static int hf_ucp_parm_XSer = -1; -static int hf_xser_service = -1; -static int hf_xser_length = -1; -static int hf_xser_data = -1; +static int hf_ucp_oper_section; +static int hf_ucp_parm_AdC; +static int hf_ucp_parm_OAdC; +static int hf_ucp_parm_DAdC; +static int hf_ucp_parm_AC; +static int hf_ucp_parm_OAC; +static int hf_ucp_parm_BAS; +static int hf_ucp_parm_LAR; +static int hf_ucp_parm_LAC; +static int hf_ucp_parm_L1R; +static int hf_ucp_parm_L1P; +static int hf_ucp_parm_L3R; +static int hf_ucp_parm_L3P; +static int hf_ucp_parm_LCR; +static int hf_ucp_parm_LUR; +static int hf_ucp_parm_LRR; +static int hf_ucp_parm_RT; +static int hf_ucp_parm_NoN; +static int hf_ucp_parm_NoA; +static int hf_ucp_parm_NoB; +static int hf_ucp_parm_NAC; +static int hf_ucp_parm_PNC; +static int hf_ucp_parm_AMsg; +static int hf_ucp_parm_LNo; +static int hf_ucp_parm_LST; +static int hf_ucp_parm_TNo; +static int hf_ucp_parm_CS; +static int hf_ucp_parm_PID; +static int hf_ucp_parm_NPL; +static int hf_ucp_parm_GA; +static int hf_ucp_parm_RP; +static int hf_ucp_parm_LRP; +static int hf_ucp_parm_PR; +static int hf_ucp_parm_LPR; +static int hf_ucp_parm_UM; +static int hf_ucp_parm_LUM; +static int hf_ucp_parm_RC; +static int hf_ucp_parm_LRC; +static int hf_ucp_parm_NRq; +static int hf_ucp_parm_GAdC; +static int hf_ucp_parm_A_D; +static int hf_ucp_parm_CT; +static int hf_ucp_parm_AAC; +static int hf_ucp_parm_MNo; +static int hf_ucp_parm_R_T; +static int hf_ucp_parm_IVR5x; +static int hf_ucp_parm_REQ_OT; +static int hf_ucp_parm_SSTAT; +static int hf_ucp_parm_LMN; +static int hf_ucp_parm_NMESS; +static int hf_ucp_parm_NAdC; +static int hf_ucp_parm_NT; +static int hf_ucp_parm_NPID; +static int hf_ucp_parm_LRq; +static int hf_ucp_parm_LRAd; +static int hf_ucp_parm_LPID; +static int hf_ucp_parm_DD; +static int hf_ucp_parm_DDT; +static int hf_ucp_parm_STx; +static int hf_ucp_parm_ST; +static int hf_ucp_parm_SP; +static int hf_ucp_parm_VP; +static int hf_ucp_parm_RPID; +static int hf_ucp_parm_SCTS; +static int hf_ucp_parm_Dst; +static int hf_ucp_parm_Rsn; +static int hf_ucp_parm_DSCTS; +static int hf_ucp_parm_MT; +static int hf_ucp_parm_NB; +static int hf_ucp_data_section; +static int hf_ucp_parm_MMS; +static int hf_ucp_parm_DCs; +static int hf_ucp_parm_MCLs; +static int hf_ucp_parm_RPI; +static int hf_ucp_parm_CPg; +static int hf_ucp_parm_RPLy; +static int hf_ucp_parm_OTOA; +static int hf_ucp_parm_HPLMN; +static int hf_ucp_parm_RES4; +static int hf_ucp_parm_RES5; +static int hf_ucp_parm_OTON; +static int hf_ucp_parm_ONPI; +static int hf_ucp_parm_STYP0; +static int hf_ucp_parm_STYP1; +static int hf_ucp_parm_ACK; +static int hf_ucp_parm_PWD; +static int hf_ucp_parm_NPWD; +static int hf_ucp_parm_VERS; +static int hf_ucp_parm_LAdC; +static int hf_ucp_parm_LTON; +static int hf_ucp_parm_LNPI; +static int hf_ucp_parm_OPID; +static int hf_ucp_parm_RES1; +static int hf_ucp_parm_RES2; +static int hf_ucp_parm_MVP; +static int hf_ucp_parm_EC; +static int hf_ucp_parm_SM; +static int hf_ucp_not_subscribed; +static int hf_ucp_ga_roaming; +static int hf_ucp_call_barring; +static int hf_ucp_deferred_delivery; +static int hf_ucp_diversion; + +static int hf_ucp_parm_XSer; +static int hf_xser_service; +static int hf_xser_length; +static int hf_xser_data; /* Initialize the subtree pointers */ -static gint ett_ucp = -1; -static gint ett_sub = -1; -static gint ett_XSer = -1; +static gint ett_ucp; +static gint ett_sub; +static gint ett_XSer; -static expert_field ei_ucp_stx_missing = EI_INIT; -static expert_field ei_ucp_intstring_invalid = EI_INIT; +static expert_field ei_ucp_stx_missing; +static expert_field ei_ucp_intstring_invalid; +static expert_field ei_ucp_hexstring_invalid; +static expert_field ei_ucp_short_data; /* Tap */ -static int ucp_tap = -1; +static int ucp_tap; /* * Value-arrays for certain field-contents @@ -510,6 +513,12 @@ static const value_string vals_parm_RC[] = { { 0, NULL }, }; +static const value_string vals_parm_OTOA[] = { + { 1139, "The OAdC is set to NPI telephone and TON international" }, + { 5039, "The OAdC contains an alphanumeric address" }, + { 0, NULL } +}; + static const value_string vals_parm_OTON[] = { { '1', "International number" }, { '2', "National number" }, @@ -669,7 +678,8 @@ static tap_packet_status ucp_stats_tree_per_packet(stats_tree *st, /* st as it was passed to us */ packet_info *pinfo _U_, epan_dissect_t *edt _U_, - const void *p) /* Used for getting UCP stats */ + const void *p, + tap_flags_t flags _U_) /* Used for getting UCP stats */ { const ucp_tap_rec_t *tap_rec = (const ucp_tap_rec_t*)p; @@ -794,7 +804,7 @@ ucp_mktime(const gint len, const char *datestr) /*! * Scanning routines to add standard types (byte, int, string, data) - * to the protocol-tree. Each field is seperated with a slash ('/'). + * to the protocol-tree. Each field is separated with a slash ('/'). * * \param tree The protocol tree to add to * \param tvb Buffer containing the data @@ -803,9 +813,10 @@ ucp_mktime(const gint len, const char *datestr) * of next field. * */ -static void +static proto_item* ucp_handle_string(proto_tree *tree, tvbuff_t *tvb, int field, int *offset) { + proto_item *ti = NULL; gint idx, len; idx = tvb_find_guint8(tvb, *offset, -1, '/'); @@ -816,61 +827,57 @@ ucp_handle_string(proto_tree *tree, tvbuff_t *tvb, int field, int *offset) } else len = idx - *offset; if (len > 0) - proto_tree_add_item(tree, field, tvb, *offset, len, ENC_ASCII|ENC_NA); + ti = proto_tree_add_item(tree, field, tvb, *offset, len, ENC_ASCII|ENC_NA); *offset += len; if (idx != -1) *offset += 1; /* skip terminating '/' */ + return ti; } -#define UCP_BUFSIZ 512 - static void ucp_handle_IRAstring(proto_tree *tree, tvbuff_t *tvb, int field, int *offset) { - char strval[UCP_BUFSIZ + 1], - *p_dst = strval; - guint8 byte; - int idx = 0; - int tmpoff = *offset; + GByteArray *bytes; + wmem_strbuf_t *strbuf; + char *strval = NULL; + int idx, len; + int tmpoff; - while (((byte = tvb_get_guint8(tvb, tmpoff++)) != '/') && - (idx < UCP_BUFSIZ)) - { - if (byte >= '0' && byte <= '9') - { - *p_dst = (byte - '0') * 16; - } - else - { - *p_dst = (byte - 'A' + 10) * 16; - } - if ((byte = tvb_get_guint8(tvb, tmpoff++)) == '/') - { - break; - } - if (byte >= '0' && byte <= '9') - { - *p_dst++ += byte - '0'; - } - else - { - *p_dst++ += byte - 'A' + 10; + idx = tvb_find_guint8(tvb, *offset, -1, '/'); + if (idx == -1) { + /* Force the appropriate exception to be thrown. */ + len = tvb_captured_length_remaining(tvb, *offset); + tvb_ensure_bytes_exist(tvb, *offset, len + 1); + } else { + len = idx - *offset; + } + bytes = g_byte_array_sized_new(len); + if (tvb_get_string_bytes(tvb, *offset, len, ENC_ASCII|ENC_STR_HEX|ENC_SEP_NONE, bytes, &tmpoff)) { + strval = get_ts_23_038_7bits_string_unpacked(wmem_packet_scope(), bytes->data, bytes->len); + } + strbuf = wmem_strbuf_new(wmem_packet_scope(), strval); + while ((tmpoff + 1) < idx) { + wmem_strbuf_append_unichar_repl(strbuf); + tmpoff += 2; + if ((tmpoff + 1) >= idx) break; + bytes = g_byte_array_set_size(bytes, 0); + if (tvb_get_string_bytes(tvb, tmpoff, idx-tmpoff, ENC_ASCII|ENC_STR_HEX|ENC_SEP_NONE, bytes, &tmpoff)) { + strval = get_ts_23_038_7bits_string_unpacked(wmem_packet_scope(), bytes->data, bytes->len); + wmem_strbuf_append(strbuf, strval); } - idx++; } - strval[idx] = '\0'; - if (idx == UCP_BUFSIZ) - { - /* - * Data clipped, eat rest of field - */ - while ((tvb_get_guint8(tvb, tmpoff++)) != '/') - ; + if (tmpoff < idx) { + /* Odd string length, which is impossible and indicates an error. */ + wmem_strbuf_append_unichar_repl(strbuf); } - if ((tmpoff - *offset) > 1) + g_byte_array_free(bytes, TRUE); + if (len > 0) { proto_tree_add_string(tree, field, tvb, *offset, - tmpoff - *offset - 1, strval); - *offset = tmpoff; + len, wmem_strbuf_finalize(strbuf)); + } + *offset += len; + if (idx != -1) + *offset += 1; /* skip terminating '/' */ } static guint @@ -1042,11 +1049,64 @@ ucp_handle_XSer(proto_tree *tree, tvbuff_t *tvb) len = len * 16 + AHex2Bin(intval); proto_tree_add_uint(tree, hf_xser_service, tvb, offset, 2, service); proto_tree_add_uint(tree, hf_xser_length, tvb, offset+2, 2, len); - proto_tree_add_item(tree, hf_xser_data, tvb, offset+4, len*2, ENC_ASCII|ENC_NA); + proto_tree_add_item(tree, hf_xser_data, tvb, offset+4, len*2, ENC_ASCII); offset += 4 + (2 * len); } } +static proto_item* +ucp_handle_alphanum_OAdC(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int field, int *offset) +{ + proto_item *ti = NULL; + GByteArray *bytes; + char *strval = NULL; + int idx, len; + int tmpoff; + + idx = tvb_find_guint8(tvb, *offset, -1, '/'); + if (idx == -1) { + /* Force the appropriate exception to be thrown. */ + len = tvb_captured_length_remaining(tvb, *offset); + tvb_ensure_bytes_exist(tvb, *offset, len + 1); + } else { + len = idx - *offset; + } + + if (len == 0) { + if (idx != -1) + *offset += 1; /* skip terminating '/' */ + return ti; + } + + bytes = g_byte_array_sized_new(len); + if (tvb_get_string_bytes(tvb, *offset, len, ENC_ASCII|ENC_STR_HEX|ENC_SEP_NONE, bytes, &tmpoff)) { + /* If this returns true, there's at least one byte */ + unsigned addrlength = bytes->data[0]; // expected number of semi-octets/nibbles + unsigned numdigocts = (addrlength + 1) / 2; + int no_of_chars = (addrlength << 2) / 7; + if (bytes->len + 1 < numdigocts) { + // Short data + proto_tree_add_expert(tree, pinfo, &ei_ucp_short_data, tvb, *offset, len); + no_of_chars = ((bytes->len - 1) << 3) / 7; + } + strval = get_ts_23_038_7bits_string_packed(pinfo->pool, &bytes->data[1], 0, no_of_chars); + } + g_byte_array_free(bytes, TRUE); + ti = proto_tree_add_string(tree, field, tvb, *offset, + len, strval); + if (tmpoff < *offset + len) { + /* We didn't consume all the bytes, so either a failed conversion + * from ASCII hex bytes, or an odd number of bytes. + */ + expert_add_info(pinfo, ti, &ei_ucp_hexstring_invalid); + } + *offset += len; + if (idx != -1) + *offset += 1; /* skip terminating '/' */ + + return ti; +} + /* Next definitions are just a convenient shorthand to make the coding a * bit more readable instead of summing up all these parameters. */ @@ -1630,12 +1690,13 @@ add_5xO(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb) { /* 50-series operations */ guint intval; int offset = 1; - int tmpoff; - proto_item *ti; + int tmpoff, oadc_offset; + proto_item *ti, *oadc_item; tvbuff_t *tmptvb; UcpHandleString(hf_ucp_parm_AdC); - UcpHandleString(hf_ucp_parm_OAdC); + oadc_offset = offset; + oadc_item = UcpHandleString(hf_ucp_parm_OAdC); UcpHandleString(hf_ucp_parm_AC); UcpHandleByte(hf_ucp_parm_NRq); UcpHandleString(hf_ucp_parm_NAdC); @@ -1673,7 +1734,14 @@ add_5xO(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb) "(reserved for Reply type)"); offset++; } - UcpHandleString(hf_ucp_parm_OTOA); + intval = UcpHandleInt(hf_ucp_parm_OTOA); + if (intval == 5039) { + ti = ucp_handle_alphanum_OAdC(tree, pinfo, tvb, hf_ucp_parm_OAdC, &oadc_offset); + if (ti && oadc_item) { + proto_tree_move_item(tree, oadc_item, ti); + proto_item_set_hidden(oadc_item); + } + } UcpHandleString(hf_ucp_parm_HPLMN); tmpoff = offset; /* Extra services */ while (tvb_get_guint8(tvb, tmpoff++) != '/') @@ -2566,7 +2634,7 @@ proto_register_ucp(void) }, { &hf_ucp_parm_OTOA, { "OTOA", "ucp.parm.OTOA", - FT_STRING, BASE_NONE, NULL, 0x00, + FT_UINT16, BASE_DEC, VALS(vals_parm_OTOA), 0x00, "Originator Type Of Address.", HFILL } @@ -2784,7 +2852,9 @@ proto_register_ucp(void) static ei_register_info ei[] = { { &ei_ucp_stx_missing, { "ucp.stx_missing", PI_MALFORMED, PI_ERROR, "UCP_STX missing, this is not a new packet", EXPFILL }}, - { &ei_ucp_intstring_invalid, { "ucp.intstring.invalid", PI_MALFORMED, PI_ERROR, "Invalid integer string", EXPFILL }} + { &ei_ucp_intstring_invalid, { "ucp.intstring.invalid", PI_MALFORMED, PI_ERROR, "Invalid integer string", EXPFILL }}, + { &ei_ucp_hexstring_invalid, { "ucp.hexstring.invalid", PI_PROTOCOL, PI_WARN, "Invalid hex string", EXPFILL }}, + { &ei_ucp_short_data, { "ucp.short_data", PI_PROTOCOL, PI_WARN, "Short Data (?)", EXPFILL }} }; module_t *ucp_module; @@ -2800,6 +2870,9 @@ proto_register_ucp(void) expert_ucp = expert_register_protocol(proto_ucp); expert_register_field_array(expert_ucp, ei, array_length(ei)); + /* Register the dissector handle */ + ucp_handle = register_dissector("ucp", dissect_ucp_tcp, proto_ucp); + /* Register for tapping */ ucp_tap = register_tap("ucp"); @@ -2827,13 +2900,12 @@ proto_reg_handoff_ucp(void) /* * Also register as a dissector that can be selected by a TCP port number via "decode as". */ - ucp_handle = create_dissector_handle(dissect_ucp_tcp, proto_ucp); dissector_add_for_decode_as_with_preference("tcp.port", ucp_handle); /* Tapping setup */ - stats_tree_register_with_group("ucp", "ucp_messages", "_UCP Messages", 0, - ucp_stats_tree_per_packet, ucp_stats_tree_init, - NULL, REGISTER_STAT_GROUP_TELEPHONY); + stats_tree_cfg *st_config = stats_tree_register("ucp", "ucp_messages", "_UCP Messages", 0, + ucp_stats_tree_per_packet, ucp_stats_tree_init, NULL); + stats_tree_set_group(st_config, REGISTER_STAT_GROUP_TELEPHONY); } /* |