aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-ipdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-ipdc.c')
-rw-r--r--epan/dissectors/packet-ipdc.c442
1 files changed, 442 insertions, 0 deletions
diff --git a/epan/dissectors/packet-ipdc.c b/epan/dissectors/packet-ipdc.c
new file mode 100644
index 0000000000..e2378ba6e2
--- /dev/null
+++ b/epan/dissectors/packet-ipdc.c
@@ -0,0 +1,442 @@
+/* packet-ipdc.c
+ * Routines for IP Device Control (SS7 over IP) dissection
+ * Copyright Lucent Technologies 2004
+ * Josh Bailey <joshbailey@lucent.com> and Ruud Linders <ruud@lucent.com>
+ *
+ * Using IPDC spec 0.20.2
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <math.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include "packet-ipdc.h"
+#include "packet-tcp.h"
+#include <epan/packet.h>
+#include "ipproto.h"
+#include "prefs.h"
+
+static int proto_ipdc = -1;
+static int hf_ipdc_nr = -1;
+static int hf_ipdc_ns = -1;
+static int hf_ipdc_payload_len = -1;
+static int hf_ipdc_protocol_id = -1;
+static int hf_ipdc_trans_id_size = -1;
+static int hf_ipdc_trans_id = -1;
+static int hf_ipdc_message_code = -1;
+
+static gint ett_ipdc = -1;
+static gint ett_ipdc_tag = -1;
+
+static gboolean ipdc_desegment = TRUE;
+static gint ipdc_port_pref = TCP_PORT_IPDC;
+static gboolean new_packet = FALSE;
+
+static dissector_handle_t q931_handle;
+
+void proto_reg_handoff_ipdc(void);
+
+
+static guint
+get_ipdc_pdu_len(tvbuff_t *tvb, int offset)
+{
+ return tvb_get_ntohs(tvb,offset+2)+4;
+}
+
+static void
+dissect_ipdc_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ti;
+ proto_tree *ipdc_tree;
+ proto_item *ipdc_tag;
+ proto_tree *tag_tree;
+ tvbuff_t *q931_tvb;
+
+ char *des;
+ char *enum_val;
+ char *tmp_str;
+ char tmp_tag_text[IPDC_STR_LEN + 1];
+ const value_string *val_ptr;
+ guint32 type;
+ guint len;
+ guint i;
+ guint status;
+ gshort tag;
+ guint32 tmp_tag;
+
+ gshort nr = tvb_get_guint8(tvb,0);
+ gshort ns = tvb_get_guint8(tvb,1);
+ guint16 payload_len = (guint16) get_ipdc_pdu_len(tvb,0);
+
+ gshort protocol_id;
+ gshort trans_id_size;
+ guint32 trans_id;
+ guint16 message_code;
+ guint16 offset;
+
+ /* display IPDC protocol ID */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPDC");
+
+ /* short frame... */
+ if (payload_len < 4)
+ return;
+
+ /* clear info column and display send/receive sequence numbers */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ if (new_packet == TRUE) {
+ col_clear(pinfo->cinfo, COL_INFO);
+ new_packet = FALSE;
+ }
+ col_append_fstr(pinfo->cinfo, COL_INFO, "r=%u s=%u ",
+ nr, ns);
+ }
+
+ if (payload_len == 4) {
+ if (!tree)
+ return;
+
+ ti = proto_tree_add_item(tree, proto_ipdc, tvb, 0, -1, FALSE);
+ ipdc_tree = proto_item_add_subtree(ti, ett_ipdc);
+ proto_tree_add_item(ipdc_tree, hf_ipdc_nr, tvb, 0, 1, nr);
+ proto_tree_add_item(ipdc_tree, hf_ipdc_ns, tvb, 1, 1, ns);
+ proto_tree_add_uint(ipdc_tree, hf_ipdc_payload_len, tvb, 2, 2,
+ payload_len);
+
+ return;
+ }
+
+ /* IPDC tags present - display message code and trans. ID */
+ protocol_id = tvb_get_guint8(tvb,4);
+ trans_id_size = TRANS_ID_SIZE_IPDC;
+ trans_id = tvb_get_ntohl(tvb,6);
+ message_code = tvb_get_ntohs(tvb,6+trans_id_size);
+ offset = 6 + trans_id_size + 2; /* past message_code */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ "TID=%x %s ",
+ trans_id,
+ val_to_str(message_code, message_code_vals,
+ TEXT_UNDEFINED));
+
+ if (!tree)
+ return;
+
+ ti = proto_tree_add_item(tree, proto_ipdc, tvb, 0, -1, FALSE);
+ ipdc_tree = proto_item_add_subtree(ti, ett_ipdc);
+
+ proto_tree_add_item(ipdc_tree, hf_ipdc_nr, tvb, 0, 1, nr);
+ proto_tree_add_item(ipdc_tree, hf_ipdc_ns, tvb, 1, 1, ns);
+ proto_tree_add_uint(ipdc_tree, hf_ipdc_payload_len, tvb,
+ 2, 2, payload_len);
+
+ proto_tree_add_item(ipdc_tree, hf_ipdc_protocol_id, tvb,
+ 4, 1, protocol_id);
+ proto_tree_add_item(ipdc_tree, hf_ipdc_trans_id_size, tvb,
+ 5, 1, trans_id_size);
+ proto_tree_add_item(ipdc_tree, hf_ipdc_trans_id, tvb,
+ 6, trans_id_size, trans_id);
+ proto_tree_add_item(ipdc_tree, hf_ipdc_message_code, tvb,
+ 6 + trans_id_size + 1, 1, message_code);
+
+ ipdc_tag = proto_tree_add_text(ipdc_tree, tvb, offset,
+ payload_len - offset, "IPDC tags");
+ tag_tree = proto_item_add_subtree(ipdc_tag, ett_ipdc_tag);
+
+ /* iterate through tags. first byte is tag, second is length,
+ in bytes, following is tag data. tag of 0x0 should be
+ end of tags. */
+ for (;;) {
+ tag = tvb_get_guint8(tvb, offset);
+
+ if (tag == 0x0) {
+ if (offset == payload_len - 1) {
+ proto_tree_add_text(tag_tree, tvb,
+ offset, 1, "end of tags");
+ } else {
+ proto_tree_add_text(tag_tree, tvb,
+ offset, 1, "data trailing end of tags");
+ }
+
+ break;
+ }
+
+ len = tvb_get_guint8(tvb,offset+1);
+ des = val_to_str(tag, tag_description, TEXT_UNDEFINED);
+ /* lookup tag type */
+ for (i = 0; (ipdc_tag_types[i].tag != tag &&
+ ipdc_tag_types[i].type != IPDC_UNKNOWN); i++)
+ ;
+ type = ipdc_tag_types[i].type;
+
+ tmp_tag = 0;
+
+ switch (type) {
+ /* simple IPDC_ASCII strings */
+ case IPDC_ASCII:
+ tmp_str = tvb_memdup(tvb, offset + 2, len);
+ strncpy(tmp_tag_text, tmp_str, len);
+ tmp_tag_text[len] = 0;
+ free(tmp_str);
+ proto_tree_add_text(tag_tree, tvb, offset,
+ len + 2, "0x%2.2x: %s: %s", tag, des,
+ tmp_tag_text);
+ break;
+
+ /* unsigned integers, or bytes */
+ case IPDC_UINT:
+ case IPDC_BYTE:
+ for (i = 0; i < len; i++)
+ tmp_tag += tvb_get_guint8(tvb,
+ offset + 2 + i) * (guint32)
+ pow(256, len - (i + 1));
+
+ if (len == 1)
+ enum_val =
+ val_to_str(IPDC_TAG(tag) +
+ tmp_tag,
+ tag_enum_type, TEXT_UNDEFINED);
+
+ if (len == 1 &&
+ strcmp(enum_val, TEXT_UNDEFINED) != 0) {
+ proto_tree_add_text(tag_tree, tvb,
+ offset, len + 2,
+ "0x%2.2x: %s: %s",
+ tag, des, enum_val);
+ } else {
+ proto_tree_add_text(tag_tree, tvb,
+ offset, len + 2,
+ "0x%2.2x: %s: %u",
+ tag, des, tmp_tag);
+ }
+ break;
+
+ /* IP addresses */
+ case IPDC_IPA:
+ switch (len) {
+ case 4:
+ g_snprintf(tmp_tag_text,
+ IPDC_STR_LEN,
+ "%u.%u.%u.%u",
+ tvb_get_guint8(tvb, offset + 2),
+ tvb_get_guint8(tvb, offset + 3),
+ tvb_get_guint8(tvb, offset + 4),
+ tvb_get_guint8(tvb, offset + 5)
+ );
+ break;
+
+ case 6:
+ g_snprintf(tmp_tag_text,
+ IPDC_STR_LEN,
+ "%u.%u.%u.%u:%u",
+ tvb_get_guint8(tvb, offset + 2),
+ tvb_get_guint8(tvb, offset + 3),
+ tvb_get_guint8(tvb, offset + 4),
+ tvb_get_guint8(tvb, offset + 5),
+ tvb_get_ntohs(tvb, offset + 6));
+ break;
+
+ default:
+ g_snprintf(tmp_tag_text,
+ IPDC_STR_LEN,
+ "Invalid IP address length %u",
+ len);
+ }
+
+ proto_tree_add_text(tag_tree, tvb,
+ offset, len + 2,
+ "0x%2.2x: %s: %s",
+ tag, des, tmp_tag_text);
+ break;
+
+ /* Line status arrays */
+ case IPDC_LINESTATUS:
+ case IPDC_CHANNELSTATUS:
+ proto_tree_add_text(tag_tree, tvb, offset,
+ len + 2, "0x%2.2x: %s", tag, des);
+ val_ptr = (type == IPDC_LINESTATUS) ?
+ line_status_vals : channel_status_vals;
+
+ for (i = 0; i < len; i++) {
+ status = tvb_get_guint8(tvb,offset+2+i);
+
+ proto_tree_add_text(tag_tree, tvb,
+ offset + 2 + i, 1,
+ " %.2u: %.2x (%s)",
+ i + 1, status,
+ val_to_str(status,
+ val_ptr,
+ TEXT_UNDEFINED));
+ }
+ break;
+
+ case IPDC_Q931:
+ q931_tvb =
+ tvb_new_subset(tvb, offset+2, len, len);
+ call_dissector(q931_handle,q931_tvb,pinfo,tree);
+ break;
+
+ case IPDC_ENCTYPE:
+ proto_tree_add_text(tag_tree, tvb,
+ offset, len + 2,
+ "0x%2.2x: %s: %s",
+ tag, des, val_to_str(
+ tvb_get_guint8(tvb,offset+2),
+ encoding_type_vals,
+ TEXT_UNDEFINED));
+
+ if (len == 2) {
+ proto_tree_add_text(tag_tree, tvb,
+ offset, len + 2,
+ "0x%2.2x: %s: %u",
+ tag, des,
+ tvb_get_guint8(tvb,offset+3));
+ }
+ break;
+
+ /* default */
+ default:
+ proto_tree_add_text(tag_tree, tvb, offset,
+ len + 2, "0x%2.2x: %s", tag, des);
+ } /* switch */
+
+ offset += len + 2;
+ }
+}
+
+static void
+dissect_ipdc_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ dissect_ipdc_common(tvb, pinfo, tree);
+}
+
+static void
+dissect_ipdc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ new_packet = TRUE;
+ tcp_dissect_pdus(tvb, pinfo, tree, ipdc_desegment, 4,
+ get_ipdc_pdu_len, dissect_ipdc_tcp_pdu);
+}
+
+void
+proto_register_ipdc(void)
+{
+
+ static hf_register_info hf[] = {
+ { &hf_ipdc_nr,
+ { "N(r)", "ipdc.nr",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Receive sequence number", HFILL }
+ },
+
+ { &hf_ipdc_ns,
+ { "N(s)", "ipdc.ns",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Transmit sequence number", HFILL }
+ },
+
+ { &hf_ipdc_payload_len,
+ { "Payload length", "ipdc.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Payload length", HFILL }
+ },
+
+ { &hf_ipdc_protocol_id,
+ { "Protocol ID", "ipdc.protocol_id",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Protocol ID", HFILL }
+ },
+
+ { &hf_ipdc_trans_id_size,
+ { "Transaction ID size", "ipdc.trans_id_size",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Transaction ID size", HFILL }
+ },
+
+ { &hf_ipdc_trans_id,
+ { "Transaction ID", "ipdc.trans_id",
+ FT_BYTES, BASE_HEX, NULL, 0x0,
+ "Transaction ID", HFILL }
+ },
+
+ { &hf_ipdc_message_code,
+ { "Message code", "ipdc.message_code",
+ FT_UINT16, BASE_HEX, VALS(message_code_vals), 0x0,
+ "Message Code", HFILL }
+ },
+ };
+
+ static gint *ett[] = {
+ &ett_ipdc,
+ &ett_ipdc_tag,
+ };
+
+ module_t *ipdc_module;
+
+ proto_ipdc = proto_register_protocol("IP Device Control (SS7 over IP)",
+ "IPDC", "ipdc");
+ proto_register_field_array(proto_ipdc, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ ipdc_module = prefs_register_protocol(proto_ipdc, proto_reg_handoff_ipdc);
+ prefs_register_bool_preference(ipdc_module, "desegment_ipdc_messages",
+ "Desegment all IPDC messages spanning multiple TCP segments",
+ "Whether the IPDC dissector should desegment all messages spanning multiple TCP segments",
+ &ipdc_desegment);
+ prefs_register_uint_preference(ipdc_module, "tcp.port",
+ "IPDC monitoring port",
+ "Set the IPDC monitoring port", 10,
+ &ipdc_port_pref);
+}
+
+void
+proto_reg_handoff_ipdc(void)
+{
+ static gint last_ipdc_port_pref = 0;
+ static dissector_handle_t ipdc_tcp_handle = NULL;
+
+ if (ipdc_tcp_handle) {
+ dissector_delete("tcp.port", last_ipdc_port_pref,
+ ipdc_tcp_handle);
+ } else {
+ ipdc_tcp_handle =
+ create_dissector_handle(dissect_ipdc_tcp, proto_ipdc);
+ q931_handle = find_dissector("q931");
+ }
+
+ last_ipdc_port_pref = ipdc_port_pref;
+ dissector_add("tcp.port", ipdc_port_pref, ipdc_tcp_handle);
+}