aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-ucp.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-ucp.c')
-rw-r--r--epan/dissectors/packet-ucp.c420
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);
}
/*