aboutsummaryrefslogtreecommitdiffstats
path: root/packet-gsm_map.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2003-12-03 23:54:50 +0000
committerGuy Harris <guy@alum.mit.edu>2003-12-03 23:54:50 +0000
commit78191a09b5cd5840a8cc94879094f63b808ba1e8 (patch)
tree8bf9f4695bfd8a400041d67a45a8e683ab3c7484 /packet-gsm_map.c
parent56c65fa63b3ac370d6194e45873c4815af19f8c8 (diff)
From Felix Fei: GSM MAP support.
From Michael Lum: Modified for better TCAP separation, fixed EOC handling (a la TCAP). Added parameter parsing (although not dissection or naming). svn path=/trunk/; revision=9160
Diffstat (limited to 'packet-gsm_map.c')
-rw-r--r--packet-gsm_map.c1586
1 files changed, 1586 insertions, 0 deletions
diff --git a/packet-gsm_map.c b/packet-gsm_map.c
new file mode 100644
index 0000000000..3adf98b858
--- /dev/null
+++ b/packet-gsm_map.c
@@ -0,0 +1,1586 @@
+/* packet-gsm_map.c
+ * Routines for GSM Mobile Application Part dissection
+ *
+ * Copyright 2000, Felix Fei <felix.fei [AT] utstar.com>
+ *
+ * Michael Lum <mlum [AT] telostech.com>,
+ * Changed to run on new version of TCAP, many changes for
+ * EOC matching, and parameter separation. (2003)
+ *
+ * $Id: packet-gsm_map.c,v 1.1 2003/12/03 23:54:50 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from packet-tcap.c (where "WHATEVER_FILE_YOU_USED"
+ * is a dissector file; if you just copied this from README.developer,
+ * don't bother with the "Copied from" - you don't even need to put
+ * in a "Copied from" if you copied an existing dissector, especially
+ * if the bulk of the code in the new dissector is your code)
+ *
+ * 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 "epan/packet.h"
+#include "asn1.h"
+
+
+/* OPERATION CODE DEFINITION */
+
+/* LOCATION MANAGEMENT */
+#define MAP_UPD_LOC 2 /* Update Location */
+#define MAP_CANCEL_LOC 3 /* Cancel Location */
+#define MAP_PURGE 67 /* Purge MS */
+#define MAP_SEND_ID 5 /* Send Identification */
+#define MAP_GPRS_UPD_LOC 23 /* GPRS Update Location */
+#define MAP_DET_IMSI 5 /* Detach IMSI */
+#define MAP_NOTE_MM_EVT 89 /* Note MM Event */
+
+/* HANDOVER MANAGEMENT */
+#define MAP_PREP_HO 68 /* Prepare Handover */
+#define MAP_PREP_SUBS_HO 69 /* Prepare Subsequent Handover */
+#define MAP_PERF_HO 28 /* Perform Handover */
+#define MAP_PERF_SUBS_HO 30 /* Perform Subsequent Handover */
+#define MAP_SEND_END_SIG 29 /* Send End Signal */
+#define MAP_PROC_ACC_SIG 33 /* Process Access Signalling */
+#define MAP_FWD_ACC_SIG 34 /* Forward Access Signalling */
+
+/* AUTHENTICATION MANAGEMENT */
+#define MAP_AUTH_INFO 56 /* Send Authintication Info */
+#define MAP_AUTH_FAIL_RPT 15 /* Authentication Failure Report */
+
+/* IDENTIFICATION MANAGEMENT */
+#define MAP_CHK_IMEI 43 /* Check IMEI */
+
+/* FAULT & RECOVERY MANAGEMENT */
+#define MAP_RESET 37 /* Reset */
+#define MAP_RESTORE_DATA 57 /* Restore Data */
+#define MAP_FWD_CHK_SS_IND 38 /* Forward Check SS Indication */
+
+/* OAM MANAGEMENT */
+#define MAP_ACT_TRACE 50 /* Activate Trace */
+#define MAP_DEACT_TRACE 51 /* Deactivate Trace Mode */
+#define MAP_SEND_IMSI 58 /* Send IMSI */
+#define MAP_TRACE_SUBS_ACTV 52 /* Trace Subscriber Activity */
+#define MAP_NOTE_INTER_HO 35 /* Not Internal Handover */
+
+/* CALL MANAGEMENT */
+#define MAP_ROUTE_INFO 22 /* Send Routing Info */
+#define MAP_PROV_ROAM_NUM 4 /* Provide Roaming Number */
+#define MAP_PROV_SIWFS_NUM 31 /* Provide SIWFS Number */
+#define MAP_SIWFS_SIG_MOD 32 /* SIWFS Signalling Modify */
+#define MAP_RES_CALL_HAND 6 /* Resume Call Handling */
+#define MAP_SET_RPT_STATE 73 /* Set Reporting State */
+#define MAP_STAT_RPT 74 /* Status Report */
+#define MAP_REM_USR_FREE 75 /* Remote user free */
+#define MAP_PREP_GRP_CALL 39 /* Prepare Group Call */
+#define MAP_SND_GRP_CALL_END_SIG 40 /* Send Group Call End Signalling */
+#define MAP_PRO_GRP_CALL_SIG 41 /* Process Group Call Signalling */
+#define MAP_FWD_GRP_CALL_SIG 42 /* Forward Group Call Signalling */
+#define MAP_IST_ALERT 87 /* IST Alert */
+#define MAP_IST_COMMAND 88 /* IST Command */
+
+/* SS MANAGEMENT */
+#define MAP_REG_SS 10 /* Register SS */
+#define MAP_ERASE_SS 11 /* Erase SS */
+#define MAP_ACT_SS 12 /* Activate SS */
+#define MAP_DEACT_SS 13 /* Deactivate SS */
+#define MAP_INTER_SS 14 /* Interogate SS */
+#define MAP_PROC_U_SS_REQ 59 /* Process Unstructured SS Req */
+#define MAP_U_SS_REQ 60 /* Unstructured SS Request */
+#define MAP_U_SS_NOTIFY 61 /* Unstructured SS Notify */
+#define MAP_REG_PASSWD 17 /* Register Password */
+#define MAP_GET_PASSWD 18 /* Get Password */
+#define MAP_REG_CC_ENT 76 /* Register CC Entry */
+#define MAP_ERASE_CC_ENT 77 /* Erase CC Entry */
+#define MAP_BEGIN_SUBS_ACTV 54 /* Begin Subscriber Activity */
+#define MAP_PROC_U_SS_DATA 19 /* Process Unstructured SS Data */
+#define MAP_SS_INV_NOTIFY 72 /* SS Invocation Notify */
+
+/* SMS MANAGEMENT */
+#define MAP_MO_FWD_SM 46 /* Forward Short Message */
+#define MAP_MT_FWD_SM 44 /* MT-Fwd SM */
+#define MAP_ROUTE_INFO_SM 45 /* Routing Info for SM */
+#define MAP_SM_DEL_STAT 47 /* Report SM Delivery Status */
+#define MAP_INFORM_SC 63 /* Inform Service Center */
+#define MAP_ALERT_SC 64 /* Alert Service Center */
+#define MAP_SM_READY 66 /* SM Ready */
+#define MAP_NOTE_SUB_PRES 48 /* Note Subscriber Present */
+#define MAP_ALERT_SC_W_RES 49 /* Alert SC Without Result */
+
+/* SUBSCRIBER MANAGEMENT */
+#define MAP_INS_SUB_DATA 7 /* Insert Subscriber Data */
+#define MAP_DEL_SUB_DATA 8 /* Delete Subscriber Data */
+#define MAP_PROV_SUB_INFO 70 /* Provide Subscriber Info */
+#define MAP_ANY_TIME_INTER 71 /* Any Time Interrogation */
+#define MAP_SEND_PARAM 9 /* Send Parameters */
+#define MAP_ANY_TIME_SUB_DATA_INTER 62 /* Any Time Subscriber Info Interrogation */
+#define MAP_ANY_TIME_MOD 65 /* Any Time Modification */
+#define MAP_NOTE_SUB_DATA_MOD 5 /* Note Subscriber Data Modified */
+
+/* PDP ACTIVE MANAGEMENT */
+#define MAP_GPRS_ROUTE_INFO 24 /* Rout Info for GPRS */
+#define MAP_FAIL_REP 25 /* Failure Report */
+#define MAP_GPRS_NOTE_MS_PRES 26 /* GPRS NoteMs Present */
+
+/* LOCATION SERVICE */
+#define MAP_PROV_SUB_LOC 83 /* Provide Subscriber Location */
+#define MAP_SEND_ROUTE_INFO_FOR_LCS 85 /* Send Routing Info For LCS */
+#define MAP_SUB_LOC_REP 86 /* Subscriber Location Report */
+
+
+#define MAP_OPR_CODE_TAG 0x02
+#define MAP_INVOKE_ID_TAG 0x02
+#define MAP_LINK_ID_TAG 0x80
+#define MAP_SEQ_TAG 0x30
+#define MAP_GE_PROBLEM_TAG 0x80
+#define MAP_IN_PROBLEM_TAG 0x81
+#define MAP_RR_PROBLEM_TAG 0x82
+#define MAP_RE_PROBLEM_TAG 0x83
+#define MAP_INVALID_TAG 0x00
+
+#define MAP_OK 0x0
+#define MAP_FAIL 0x1
+
+static const value_string opr_code_strings[] = {
+
+/* LOCATION MANAGEMENT */
+ { MAP_UPD_LOC, "Update Location"},
+ { MAP_CANCEL_LOC, "Cancel Location"},
+ { MAP_PURGE, "Purge MS"},
+ { MAP_SEND_ID, "Send Identification"},
+ { MAP_GPRS_UPD_LOC, "Update GPRS Location"},
+ { MAP_DET_IMSI, "Detach IMSI"},
+ { MAP_NOTE_MM_EVT, "Note MM Event"},
+
+/* HANDOVER MANAGEMENT */
+ { MAP_PREP_HO, "Prepare Handover"},
+ { MAP_PREP_SUBS_HO, "Prepare Subsequent Handover"},
+ { MAP_PERF_HO, "Perform Handover"},
+ { MAP_PERF_SUBS_HO, "Perform Subsequent Handover"},
+ { MAP_SEND_END_SIG, "Send End Signal"},
+ { MAP_PROC_ACC_SIG, "Process Access Signalling"},
+ { MAP_FWD_ACC_SIG, "Forward Access Signalling"},
+
+/* AUTHENTICATION MANAGEMENT */
+ { MAP_AUTH_INFO, "Send Authentication Info"},
+ { MAP_AUTH_FAIL_RPT, "Authentication Failure Report"},
+
+/* IDENTIFICATION MANAGEMENT */
+ { MAP_CHK_IMEI, "Check IMEI"},
+
+/* FAULT & RECOVERY MANAGEMENT */
+ { MAP_RESET, "Reset"},
+ { MAP_RESTORE_DATA, "Restore Data"},
+ { MAP_FWD_CHK_SS_IND, "Forward Check SS Indication"},
+
+/* OAM MANAGEMENT */
+ { MAP_ACT_TRACE, "Activate Trace Mode"},
+ { MAP_DEACT_TRACE, "Deactivate Trace Mode"},
+ { MAP_SEND_IMSI, "Send IMSI"},
+ { MAP_TRACE_SUBS_ACTV, "Trace Subscriber Activity"},
+ { MAP_NOTE_INTER_HO, "Note Internal Handover"},
+
+/* CALL MANAGEMENT */
+ { MAP_ROUTE_INFO, "Send Routing Info"},
+ { MAP_PROV_ROAM_NUM, "Provide Roaming Number"},
+ { MAP_PROV_SIWFS_NUM, "Provide SIWFS Number"},
+ { MAP_SIWFS_SIG_MOD, "SIWFS Signalling Modify"},
+ { MAP_RES_CALL_HAND, "Resume Call Handling"},
+ { MAP_SET_RPT_STATE, "Set Reporting State"},
+ { MAP_STAT_RPT, "Status Report"},
+ { MAP_REM_USR_FREE, "Remote User Free"},
+ { MAP_PREP_GRP_CALL, "Prepare Group Call"},
+ { MAP_SND_GRP_CALL_END_SIG, "Send Group Call End Signalling"},
+ { MAP_PRO_GRP_CALL_SIG, "Process Group Call Signalling"},
+ { MAP_FWD_GRP_CALL_SIG, "Forward Group Call Signalling"},
+ { MAP_IST_ALERT, "IST Alert"},
+ { MAP_IST_COMMAND, "IST Command"},
+
+/* SS MANAGEMENT */
+ { MAP_REG_SS, "Register SS"},
+ { MAP_ERASE_SS, "Erase SS"},
+ { MAP_ACT_SS, "Activate SS"},
+ { MAP_DEACT_SS, "Deactivate SS"},
+ { MAP_INTER_SS, "Interogate SS"},
+ { MAP_PROC_U_SS_REQ, "Process Unstructured SS Request"},
+ { MAP_U_SS_REQ, "Unstructured SS Request"},
+ { MAP_U_SS_NOTIFY, "Unstructured SS Notify"},
+ { MAP_REG_PASSWD, "Register Password"},
+ { MAP_GET_PASSWD, "Get Password"},
+ { MAP_REG_CC_ENT, "Register CC Entry"},
+ { MAP_ERASE_CC_ENT, "Erase CC Entry"},
+ { MAP_BEGIN_SUBS_ACTV, "Begin Subscriber Activity"},
+ { MAP_PROC_U_SS_DATA, "Process Unstructured SS Data"},
+ { MAP_SS_INV_NOTIFY, "SS Invocation Notification"},
+
+/* SMS MANAGEMENT */
+ { MAP_MO_FWD_SM, "MO Forward SM"},
+ { MAP_MT_FWD_SM, "MT Forward SM"},
+ { MAP_ROUTE_INFO_SM, "Send Routing Info For SM"},
+ { MAP_SM_DEL_STAT, "Report SM Delivery Status"},
+ { MAP_INFORM_SC, "Inform Service Center"},
+ { MAP_ALERT_SC, "Alert Service Center"},
+ { MAP_SM_READY, "Ready For SM"},
+ { MAP_NOTE_SUB_PRES, "Note Subscriber Present"},
+ { MAP_ALERT_SC_W_RES, "Alert SC Without Result"},
+
+/* SUBSCRIBER MANAGEMENT */
+ { MAP_INS_SUB_DATA, "Insert Subscriber Data"},
+ { MAP_DEL_SUB_DATA, "Delete Subscriber Data"},
+ { MAP_PROV_SUB_INFO, "Provide Subscriber Info"},
+ { MAP_ANY_TIME_INTER, "Any Time Interrogation"},
+ { MAP_SEND_PARAM, "Send Parameters"},
+ { MAP_ANY_TIME_SUB_DATA_INTER, "Any Time Subscription Interrogation"},
+ { MAP_ANY_TIME_MOD, "Any Time Modification"},
+ { MAP_NOTE_SUB_DATA_MOD, "Note Subscriber Data Modified"},
+
+/* PDP ACTIVE MANAGEMENT */
+ { MAP_GPRS_ROUTE_INFO, "Send Routing Info For GPRS"},
+ { MAP_FAIL_REP, "Failure Report"},
+ { MAP_GPRS_NOTE_MS_PRES, "Note MS Present For GPRS"},
+
+/* LOCATION SERVICE */
+ { MAP_PROV_SUB_LOC, "Provide Subscriber Location"},
+ { MAP_SEND_ROUTE_INFO_FOR_LCS, "Send Routing Info For LCS"},
+ { MAP_SUB_LOC_REP, "Subscriber Location Report"},
+
+ { 0, NULL},
+};
+
+/* TCAP component type */
+#define MAP_TC_INVOKE 0xa1
+#define MAP_TC_RRL 0xa2
+#define MAP_TC_RE 0xa3
+#define MAP_TC_REJECT 0xa4
+#define MAP_TC_RRN 0xa7
+
+static const value_string tag_strings[] = {
+ { MAP_TC_INVOKE, "Invoke" },
+ { MAP_TC_RRL, "RetRes(Last)" },
+ { MAP_TC_RE, "RetErr" },
+ { MAP_TC_REJECT, "Reject" },
+ { MAP_TC_RRN, "RetRes(Not Last)" },
+ { 0, NULL},
+};
+
+/* Initialize the protocol and registered fields */
+static int proto_map = -1;
+static int hf_map_tag = -1;
+static int hf_map_length = -1;
+static int hf_map_opr_code = -1;
+static int hf_map_int = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_map = -1;
+static gint ett_component = -1;
+static gint ett_components = -1;
+static gint ett_param = -1;
+static gint ett_params = -1;
+static gint ett_problem = -1;
+static gint ett_opr_code = -1;
+
+static const value_string param_1_strings[] = {
+ { 0x04, "IMSI" },
+ { 0x81, "msc-Number" },
+ { 0, NULL },
+};
+
+
+typedef struct dgt_set_t
+{
+ unsigned char out[15];
+}
+dgt_set_t;
+
+static dgt_set_t Dgt_tbcd = {
+ {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e */
+ '0','1','2','3','4','5','6','7','8','9','?','B','C','*','#'
+ }
+};
+
+static dgt_set_t Dgt_msid = {
+ {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e */
+ '0','1','2','3','4','5','6','7','8','9','?','?','?','?','?'
+ }
+};
+
+
+/* FUNCTIONS */
+
+/*
+ * Unpack BCD input pattern into output ASCII pattern
+ *
+ * Input Pattern is supplied using the same format as the digits
+ *
+ * Returns: length of unpacked pattern
+ */
+static int
+my_dgt_tbcd_unpack(
+ char *out, /* ASCII pattern out */
+ guchar *in, /* packed pattern in */
+ int num_octs, /* Number of octets to unpack */
+ dgt_set_t *dgt /* Digit definitions */
+ )
+{
+ int cnt = 0;
+ unsigned char i;
+
+ while (num_octs)
+ {
+ /*
+ * unpack first value in byte
+ */
+ i = *in++;
+ *out++ = dgt->out[i & 0x0f];
+ cnt++;
+
+ /*
+ * unpack second value in byte
+ */
+ i >>= 4;
+
+ if (i == 0x0f) /* odd number bytes - hit filler */
+ break;
+
+ *out++ = dgt->out[i];
+ cnt++;
+ num_octs--;
+ }
+
+ *out = '\0';
+
+ return(cnt);
+}
+
+/* Generate, into "buf", a string showing the bits of a bitfield.
+ * Return a pointer to the character after that string.
+ */
+static char *
+my_decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
+{
+ int i;
+ guint32 bit;
+ char *p;
+
+ i = 0;
+ p = buf;
+ bit = 1 << (width - 1);
+
+ for (;;)
+ {
+ if (mask & bit)
+ {
+ /* This bit is part of the field. Show its value. */
+ if (val & bit)
+ {
+ *p++ = '1';
+ }
+ else
+ {
+ *p++ = '0';
+ }
+ }
+ else
+ {
+ /* This bit is not part of the field. */
+ *p++ = '.';
+ }
+
+ bit >>= 1;
+ i++;
+
+ if (i >= width) break;
+
+ if (i % 4 == 0) *p++ = ' ';
+ }
+
+ *p = '\0';
+
+ return(p);
+}
+
+
+static gchar *
+my_match_strval(guint32 val, const value_string *vs, gint *idx)
+{
+ gint i = 0;
+
+ while (vs[i].strptr) {
+ if (vs[i].value == val)
+ {
+ *idx = i;
+ return(vs[i].strptr);
+ }
+
+ i++;
+ }
+
+ *idx = -1;
+ return(NULL);
+}
+
+
+static gboolean
+check_map_tag(ASN1_SCK *asn1, guint tag)
+{
+ guint saved_offset, real_tag;
+
+ if (tvb_length_remaining(asn1->tvb, asn1->offset) <= 0)
+ {
+ return(FALSE);
+ }
+
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &real_tag);
+ asn1->offset = saved_offset;
+
+ return(tag == real_tag);
+}
+
+/* PARAMETERS */
+
+static void
+param_imsi(ASN1_SCK *asn1, proto_tree *tree, guint len)
+{
+ guint saved_offset;
+ guchar *poctets;
+ char bigbuf[1024];
+
+ saved_offset = asn1->offset;
+ asn1_string_value_decode(asn1, len, &poctets);
+
+ my_dgt_tbcd_unpack(bigbuf, poctets, len, &Dgt_msid);
+
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, len, "IMSI %s", bigbuf);
+}
+
+static void
+param_AddressString(ASN1_SCK *asn1, proto_tree *tree, guint len)
+{
+ guint saved_offset;
+ gint32 value;
+ guchar *poctets;
+ gchar *str = NULL;
+ char bigbuf[1024];
+
+ saved_offset = asn1->offset;
+ asn1_int32_value_decode(asn1, 1, &value);
+
+ my_decode_bitfield_value(bigbuf, value, 0x80, 8);
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, 1,
+ "%s : %sxtension",
+ bigbuf, (value & 0x80) ? "No E" : "E");
+
+ switch ((value & 0x70) >> 4)
+ {
+ case 0x00: str = "unknown"; break;
+ case 0x01: str = "International Number"; break;
+ case 0x02: str = "National Significant Number"; break;
+ case 0x03: str = "Network Specific Number"; break;
+ case 0x04: str = "Subscriber Number"; break;
+ case 0x05: str = "Reserved"; break;
+ case 0x06: str = "Abbreviated Number"; break;
+ case 0x07: str = "Reserved for extension"; break;
+ }
+
+ my_decode_bitfield_value(bigbuf, value, 0x70, 8);
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, asn1->offset - saved_offset,
+ "%s : %s",
+ bigbuf, str);
+
+ switch (value & 0x0f)
+ {
+ case 0x00: str = "unknown"; break;
+ case 0x01: str = "ISDN/Telephony Numbering (Rec ITU-T E.164)"; break;
+ case 0x02: str = "spare"; break;
+ case 0x03: str = "Data Numbering (ITU-T Rec. X.121)"; break;
+ case 0x04: str = "Telex Numbering (ITU-T Rec. F.69)"; break;
+ case 0x05: str = "spare"; break;
+ case 0x06: str = "Land Mobile Numbering (ITU-T Rec. E.212)"; break;
+ case 0x07: str = "spare"; break;
+ case 0x08: str = "National Numbering"; break;
+ case 0x09: str = "Private Numbering"; break;
+ case 0x0f: str = "Reserved for extension"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ my_decode_bitfield_value(bigbuf, value, 0x0f, 8);
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, asn1->offset - saved_offset,
+ "%s : %s",
+ bigbuf, str);
+
+ saved_offset = asn1->offset;
+ asn1_string_value_decode(asn1, len - 1, &poctets);
+
+ my_dgt_tbcd_unpack(bigbuf, poctets, len - 1, &Dgt_msid);
+
+ proto_tree_add_text(tree, asn1->tvb, saved_offset, len - 1,
+ "BCD Digits %s", bigbuf);
+}
+
+#define NUM_PARAM_1 (sizeof(param_1_strings)/sizeof(value_string))
+static gint ett_param_1[NUM_PARAM_1];
+static void (*param_1_fcn[])(ASN1_SCK *asn1, proto_tree *tree, guint len) = {
+ param_imsi, /* IMSI */
+ param_AddressString, /* msc-Number */
+ NULL, /* NONE */
+};
+
+
+/* MESSAGES */
+
+static void
+op_send_auth_info(ASN1_SCK *asn1, proto_tree *tree)
+{
+ void (*param_fcn)(ASN1_SCK *asn1, proto_tree *tree, guint len) = NULL;
+ guint off_tree[100], saved_offset, len_offset;
+ int num_seq;
+ guint tag, len;
+ gboolean def_len = FALSE;
+ proto_item *item_tree[100], *item;
+ proto_tree *seq_tree[100], *use_tree, *subtree;
+ gchar *str = NULL;
+ gint ett_param_idx, idx;
+
+ num_seq = 0;
+ use_tree = tree;
+
+ while ((tvb_length_remaining(asn1->tvb, asn1->offset) > 0) &&
+ (!check_map_tag(asn1, 0)))
+ {
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &tag);
+ len_offset = asn1->offset;
+ asn1_length_decode(asn1, &def_len, &len);
+
+ if (tag == MAP_SEQ_TAG)
+ {
+ item =
+ proto_tree_add_text(use_tree, asn1->tvb,
+ saved_offset, -1, "Sequence");
+
+ subtree = proto_item_add_subtree(item, ett_params);
+
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
+ saved_offset, len_offset - saved_offset, tag, "Sequence Tag");
+
+ if (!def_len)
+ {
+ proto_tree_add_text(subtree, asn1->tvb,
+ len_offset, asn1->offset - len_offset, "Length: Indefinite");
+
+ seq_tree[num_seq] = subtree;
+ item_tree[num_seq] = item;
+ off_tree[num_seq] = saved_offset;
+ num_seq++;
+ }
+ else
+ {
+ proto_tree_add_uint(subtree, hf_map_length, asn1->tvb,
+ len_offset, asn1->offset - len_offset, len);
+
+ proto_item_set_len(item, (asn1->offset - saved_offset) + len);
+ }
+
+ use_tree = subtree;
+ continue;
+ }
+
+ if (!def_len)
+ {
+ proto_tree_add_uint_format(use_tree, hf_map_tag, asn1->tvb,
+ saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
+ proto_tree_add_text(use_tree, asn1->tvb,
+ len_offset, asn1->offset - len_offset, "Length: Indefinite");
+
+ seq_tree[num_seq] = use_tree;
+ item_tree[num_seq] = NULL;
+ num_seq++;
+ continue;
+ }
+ else
+ {
+#ifdef MLUM
+ /*
+ * XXX
+ * how do you recognize the correct parameters here ?
+ */
+ str = my_match_strval((guint32) tag, param_1_strings, &idx);
+#else
+ str = NULL;
+#endif
+
+ if (str == NULL)
+ {
+ str = "Parameter";
+ ett_param_idx = ett_param;
+ param_fcn = NULL;
+ }
+ else
+ {
+ ett_param_idx = ett_param_1[idx];
+ param_fcn = param_1_fcn[idx];
+ }
+
+ item =
+ proto_tree_add_text(use_tree, asn1->tvb,
+ saved_offset, -1, str);
+
+ subtree = proto_item_add_subtree(item, ett_param_idx);
+
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
+ saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
+
+ proto_tree_add_uint(subtree, hf_map_length, asn1->tvb,
+ len_offset, asn1->offset - len_offset, len);
+
+ proto_item_set_len(item, (asn1->offset - saved_offset) + len);
+
+ if (param_fcn == NULL)
+ {
+ proto_tree_add_text(subtree, asn1->tvb,
+ asn1->offset, len, "Parameter Data");
+
+ asn1->offset += len;
+ }
+ else
+ {
+ (*param_fcn)(asn1, subtree, len);
+ }
+ }
+
+ if (tvb_length_remaining(asn1->tvb, asn1->offset) <=0) break;
+
+ while ((num_seq > 0) &&
+ asn1_eoc(asn1, -1))
+ {
+ saved_offset = asn1->offset;
+ asn1_eoc_decode(asn1, -1);
+
+ proto_tree_add_text(seq_tree[num_seq-1], asn1->tvb,
+ saved_offset, asn1->offset - saved_offset, "End of Contents");
+
+ if (item_tree[num_seq-1] != NULL)
+ {
+ proto_item_set_len(item_tree[num_seq-1], asn1->offset - off_tree[num_seq-1]);
+ }
+
+ num_seq--;
+ }
+ }
+}
+
+#define GSM_MAP_NUM_OP (sizeof(opr_code_strings)/sizeof(value_string))
+static gint ett_op[GSM_MAP_NUM_OP];
+static void (*op_fcn[])(ASN1_SCK *asn1, proto_tree *tree) = {
+ NULL, /* Update Location */
+ NULL, /* Cancel Location */
+ NULL, /* Purge MS */
+ NULL, /* Send Identification */
+ NULL, /* Update GPRS Location */
+ NULL, /* Detach IMSI */
+ NULL, /* Note MM Event */
+ NULL, /* Prepare Handover */
+ NULL, /* Prepare Subsequent Handover */
+ NULL, /* Perform Handover */
+ NULL, /* Perform Subsequent Handover */
+ NULL, /* Send End Signal */
+ NULL, /* Process Access Signalling */
+ NULL, /* Forward Access Signalling */
+ op_send_auth_info, /* Send Authentication Info */
+ NULL, /* Authentication Failure Report */
+ NULL, /* Check IMEI */
+ NULL, /* Reset */
+ NULL, /* Restore Data */
+ NULL, /* Forward Check SS Indication */
+ NULL, /* Activate Trace Mode */
+ NULL, /* Deactivate Trace Mode */
+ NULL, /* Send IMSI */
+ NULL, /* Trace Subscriber Activity */
+ NULL, /* Note Internal Handover */
+ NULL, /* Send Routing Info */
+ NULL, /* Provide Roaming Number */
+ NULL, /* Provide SIWFS Number */
+ NULL, /* SIWFS Signalling Modify */
+ NULL, /* Resume Call Handling */
+ NULL, /* Set Reporting State */
+ NULL, /* Status Report */
+ NULL, /* Remote User Free */
+ NULL, /* Prepare Group Call */
+ NULL, /* Send Group Call End Signalling */
+ NULL, /* Process Group Call Signalling */
+ NULL, /* Forward Group Call Signalling */
+ NULL, /* IST Alert */
+ NULL, /* IST Command */
+ NULL, /* Register SS */
+ NULL, /* Erase SS */
+ NULL, /* Activate SS */
+ NULL, /* Deactivate SS */
+ NULL, /* Interogate SS */
+ NULL, /* Process Unstructured SS Request */
+ NULL, /* Unstructured SS Request */
+ NULL, /* Unstructured SS Notify */
+ NULL, /* Register Password */
+ NULL, /* Get Password */
+ NULL, /* Register CC Entry */
+ NULL, /* Erase CC Entry */
+ NULL, /* Begin Subscriber Activity */
+ NULL, /* Process Unstructured SS Data */
+ NULL, /* SS Invocation Notification */
+ NULL, /* MO Forward SM */
+ NULL, /* MT Forward SM */
+ NULL, /* Send Routing Info For SM */
+ NULL, /* Report SM Delivery Status */
+ NULL, /* Inform Service Center */
+ NULL, /* Alert Service Center */
+ NULL, /* Ready For SM */
+ NULL, /* Note Subscriber Present */
+ NULL, /* Alert SC Without Result */
+ NULL, /* Insert Subscriber Data */
+ NULL, /* Delete Subscriber Data */
+ NULL, /* Provide Subscriber Info */
+ NULL, /* Any Time Interrogation */
+ NULL, /* Send Parameters */
+ NULL, /* Any Time Subscription Interrogation */
+ NULL, /* Any Time Modification */
+ NULL, /* Note Subscriber Data Modified */
+ NULL, /* Send Routing Info For GPRS */
+ NULL, /* Failure Report */
+ NULL, /* Note MS Present For GPRS */
+ NULL, /* Provide Subscriber Location */
+ NULL, /* Send Routing Info For LCS */
+ NULL, /* Subscriber Location Report */
+
+ NULL, /* NONE */
+};
+
+
+/* GENERIC MAP DISSECTOR FUNCTIONS */
+
+static int
+dissect_map_tag(ASN1_SCK *asn1, proto_tree *tree, guint *tag, guchar * str,
+ proto_item **item_p)
+{
+ guint saved_offset, real_tag;
+
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &real_tag);
+ if ((*tag != (guint) -1) && (real_tag != *tag))
+ {
+ asn1->offset = saved_offset;
+ return(MAP_FAIL);
+ }
+
+ *item_p =
+ proto_tree_add_uint_format(tree, hf_map_tag, asn1->tvb,
+ saved_offset, asn1->offset - saved_offset,
+ real_tag, str);
+
+ return(MAP_OK);
+}
+
+
+static int
+dissect_map_len(ASN1_SCK *asn1, proto_tree *tree, gboolean *def_len, guint *len)
+{
+ guint saved_offset;
+
+ saved_offset = asn1->offset;
+ *len = 0;
+ *def_len = FALSE;
+ asn1_length_decode(asn1, def_len, len);
+
+ if (*def_len)
+ {
+ proto_tree_add_uint(tree, hf_map_length, asn1->tvb, saved_offset,
+ asn1->offset - saved_offset, *len);
+ }
+ else
+ {
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, asn1->offset - saved_offset, "Length: Indefinite");
+ }
+
+ return(MAP_OK);
+}
+
+
+static int
+dissect_map_integer(ASN1_SCK *asn1, proto_tree *tree, guint len, guchar * str)
+{
+ guint saved_offset;
+ gint32 invokeId;
+
+ saved_offset = asn1->offset;
+ asn1_int32_value_decode(asn1, len, &invokeId);
+
+ proto_tree_add_int_format(tree, hf_map_int, asn1->tvb,
+ saved_offset, asn1->offset - saved_offset,
+ invokeId, "%s %d", str, invokeId);
+
+ return(MAP_OK);
+}
+
+
+static int
+dissect_map_invokeId(ASN1_SCK *asn1, proto_tree *tree)
+{
+ guint saved_offset = 0;
+ guint len;
+ guint tag;
+ proto_item *item, *null_item;
+ proto_tree *subtree;
+ gboolean def_len;
+
+ if (check_map_tag(asn1, MAP_INVOKE_ID_TAG))
+ {
+ saved_offset = asn1->offset;
+ item =
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, -1, "Invoke Id");
+
+ subtree = proto_item_add_subtree(item, ett_component);
+
+ tag = -1;
+ dissect_map_tag(asn1, subtree, &tag, "Invoke Id Tag", &null_item);
+ dissect_map_len(asn1, subtree, &def_len, &len);
+ dissect_map_integer(asn1, subtree, len, "Invoke Id:");
+
+ proto_item_set_len(item, asn1->offset - saved_offset);
+ }
+
+ return(MAP_OK);
+}
+
+
+static void
+dissect_map_problem(ASN1_SCK *asn1, proto_tree *tree)
+{
+ guint orig_offset, saved_offset = 0;
+ guint len, tag_len;
+ guint tag;
+ proto_tree *subtree;
+ proto_item *item = NULL;
+ gchar *str = NULL;
+ gchar *type_str = NULL;
+ gint32 spec;
+ gboolean def_len;
+
+ orig_offset = asn1->offset;
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &tag);
+ tag_len = asn1->offset - saved_offset;
+
+ item =
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, -1, "Problem Code");
+
+ subtree = proto_item_add_subtree(item, ett_problem);
+
+ dissect_map_len(asn1, subtree, &def_len, &len);
+ proto_item_set_len(item, (asn1->offset - saved_offset) + len);
+
+ if (len != 1)
+ {
+ proto_tree_add_text(subtree, asn1->tvb,
+ asn1->offset, len, "Unknown encoding of Problem Code");
+
+ asn1->offset += len;
+ return;
+ }
+
+ saved_offset = asn1->offset;
+ asn1_int32_value_decode(asn1, 1, &spec);
+
+ switch (tag)
+ {
+ case MAP_GE_PROBLEM_TAG:
+ type_str = "General Problem";
+ switch (spec)
+ {
+ case 0: str = "Unrecognized Component"; break;
+ case 1: str = "Mistyped Component"; break;
+ case 2: str = "Badly Structured Component"; break;
+ default:
+ str = "Undefined";
+ break;
+ }
+ break;
+
+ case MAP_IN_PROBLEM_TAG:
+ type_str = "Invoke";
+ switch (spec)
+ {
+ case 0: str = "Duplicate Invoke ID"; break;
+ case 1: str = "Unrecognized Operation"; break;
+ case 2: str = "Mistyped Parameter"; break;
+ case 3: str = "Resource Limitation"; break;
+ case 4: str = "Initiating Release"; break;
+ case 5: str = "Unrecognized Linked ID"; break;
+ case 6: str = "Linked Response Unexpected"; break;
+ case 7: str = "Unexpected Linked Operation"; break;
+ default:
+ str = "Undefined";
+ break;
+ }
+ break;
+
+ case MAP_RR_PROBLEM_TAG:
+ type_str = "Return Result";
+ switch (spec)
+ {
+ case 0: str = "Unrecognized Invoke ID"; break;
+ case 1: str = "Return Result Unexpected"; break;
+ case 2: str = "Mistyped Parameter"; break;
+ default:
+ str = "Undefined";
+ break;
+ }
+ break;
+
+ case MAP_RE_PROBLEM_TAG:
+ type_str = "Return Error";
+ switch (spec)
+ {
+ case 0: str = "Unrecognized Invoke ID"; break;
+ case 1: str = "Return Error Unexpected"; break;
+ case 2: str = "Unrecognized Error"; break;
+ case 3: str = "Unexpected Error"; break;
+ case 4: str = "Mistyped Parameter"; break;
+ default:
+ str = "Undefined";
+ break;
+ }
+ break;
+
+ default:
+ type_str = "Undefined";
+ break;
+ }
+
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
+ orig_offset, tag_len, tag, type_str);
+
+ proto_tree_add_text(subtree, asn1->tvb,
+ saved_offset, 1, "Problem Specifier %s", str);
+}
+
+
+static int
+dissect_map_lnkId(ASN1_SCK *asn1, proto_tree *tree)
+{
+ guint saved_offset = 0;
+ guint len;
+ guint tag;
+ proto_item *item, *null_item;
+ proto_tree *subtree;
+ gboolean def_len;
+
+ if (check_map_tag(asn1, MAP_LINK_ID_TAG))
+ {
+ saved_offset = asn1->offset;
+ item =
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, -1, "Linked Id");
+
+ subtree = proto_item_add_subtree(item, ett_component);
+
+ tag = -1;
+ dissect_map_tag(asn1, tree, &tag, "Linked Id Tag", &null_item);
+ dissect_map_len(asn1, tree, &def_len, &len);
+ dissect_map_integer(asn1, tree, len, "Linked Id:");
+
+ proto_item_set_len(item, asn1->offset - saved_offset);
+ }
+
+ return(MAP_OK);
+}
+
+
+static int
+dissect_map_opr_code(ASN1_SCK *asn1, packet_info *pinfo, proto_tree *tree, gint *op_idx_p)
+{
+ guint saved_offset = 0;
+ guint len;
+ guint tag;
+ gint32 val;
+ gchar *str = NULL;
+ proto_item *item;
+ proto_tree *subtree;
+ gboolean def_len;
+
+ if (check_map_tag(asn1, MAP_OPR_CODE_TAG))
+ {
+ tag = -1;
+ dissect_map_tag(asn1, tree, &tag, "Operation Code", &item);
+ subtree = proto_item_add_subtree(item, ett_opr_code);
+ dissect_map_len(asn1, subtree, &def_len, &len);
+
+ saved_offset = asn1->offset;
+ asn1_int32_value_decode(asn1, len, &val);
+ proto_tree_add_int(subtree, hf_map_opr_code, asn1->tvb, saved_offset,
+ asn1->offset - saved_offset, val);
+
+ str = my_match_strval(val, opr_code_strings, op_idx_p);
+
+ if (NULL == str) return(MAP_FAIL);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", str);
+ }
+ }
+
+ return(MAP_OK);
+}
+
+
+static int
+dissect_map_params(ASN1_SCK *asn1, proto_tree *tree)
+{
+ guint off_tree[100], saved_offset, len_offset;
+ int num_seq;
+ guint tag, len;
+ gboolean def_len = FALSE;
+ proto_item *item_tree[100], *item;
+ proto_tree *seq_tree[100], *use_tree, *subtree;
+
+ num_seq = 0;
+ use_tree = tree;
+
+ while ((tvb_length_remaining(asn1->tvb, asn1->offset) > 0) &&
+ (!check_map_tag(asn1, 0)))
+ {
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &tag);
+ len_offset = asn1->offset;
+ asn1_length_decode(asn1, &def_len, &len);
+
+ if (tag == MAP_SEQ_TAG)
+ {
+ item =
+ proto_tree_add_text(use_tree, asn1->tvb,
+ saved_offset, -1, "Sequence");
+
+ subtree = proto_item_add_subtree(item, ett_params);
+
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
+ saved_offset, len_offset - saved_offset, tag, "Sequence Tag");
+
+ if (!def_len)
+ {
+ proto_tree_add_text(subtree, asn1->tvb,
+ len_offset, asn1->offset - len_offset, "Length: Indefinite");
+
+ seq_tree[num_seq] = subtree;
+ item_tree[num_seq] = item;
+ off_tree[num_seq] = saved_offset;
+ num_seq++;
+ }
+ else
+ {
+ proto_tree_add_uint(subtree, hf_map_length, asn1->tvb,
+ len_offset, asn1->offset - len_offset, len);
+
+ proto_item_set_len(item, (asn1->offset - saved_offset) + len);
+ }
+
+ use_tree = subtree;
+ continue;
+ }
+
+ if (!def_len)
+ {
+ proto_tree_add_uint_format(use_tree, hf_map_tag, asn1->tvb,
+ saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
+ proto_tree_add_text(use_tree, asn1->tvb,
+ len_offset, asn1->offset - len_offset, "Length: Indefinite");
+
+ seq_tree[num_seq] = use_tree;
+ item_tree[num_seq] = NULL;
+ num_seq++;
+ continue;
+ }
+ else
+ {
+ item =
+ proto_tree_add_text(use_tree, asn1->tvb,
+ saved_offset, -1, "Parameter");
+
+ subtree = proto_item_add_subtree(item, ett_param);
+
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
+ saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
+
+ proto_tree_add_uint(subtree, hf_map_length, asn1->tvb,
+ len_offset, asn1->offset - len_offset, len);
+
+ proto_item_set_len(item, (asn1->offset - saved_offset) + len);
+
+ proto_tree_add_text(subtree, asn1->tvb,
+ asn1->offset, len, "Parameter Data");
+
+ asn1->offset += len;
+ }
+
+ if (tvb_length_remaining(asn1->tvb, asn1->offset) <=0) break;
+
+ while ((num_seq > 0) &&
+ asn1_eoc(asn1, -1))
+ {
+ saved_offset = asn1->offset;
+ asn1_eoc_decode(asn1, -1);
+
+ proto_tree_add_text(seq_tree[num_seq-1], asn1->tvb,
+ saved_offset, asn1->offset - saved_offset, "End of Contents");
+
+ if (item_tree[num_seq-1] != NULL)
+ {
+ proto_item_set_len(item_tree[num_seq-1], asn1->offset - off_tree[num_seq-1]);
+ }
+
+ num_seq--;
+ }
+ }
+
+ return(MAP_OK);
+}
+
+
+static int
+dissect_map_eoc(ASN1_SCK *asn1, proto_tree *tree)
+{
+ guint saved_offset;
+
+ saved_offset = asn1->offset;
+
+ if (tvb_length_remaining(asn1->tvb, saved_offset) <= 0)
+ {
+ return(MAP_FAIL);
+ }
+
+ if (!asn1_eoc(asn1, -1))
+ {
+ return(MAP_FAIL);
+ }
+
+ asn1_eoc_decode(asn1, -1);
+
+ proto_tree_add_text(tree, asn1->tvb,
+ saved_offset, asn1->offset - saved_offset, "End of Contents");
+
+ return(MAP_OK);
+}
+
+
+static void
+dissect_map_invoke(ASN1_SCK *asn1, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *subtree;
+ guint saved_offset = 0;
+ guint len;
+ guint tag;
+ proto_item *item;
+ gint op_idx;
+ gboolean def_len;
+ int ret;
+
+ saved_offset = asn1->offset;
+ ret = asn1_id_decode1(asn1, &tag);
+ item = proto_tree_add_text(tree, asn1->tvb, saved_offset, -1, "Components");
+ subtree = proto_item_add_subtree(item, ett_components);
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
+ tag, "Invoke Type Tag");
+
+ dissect_map_len(asn1, subtree, &def_len, &len);
+
+ if (def_len)
+ {
+ proto_item_set_len(item, (asn1->offset - saved_offset) + len);
+ }
+
+ dissect_map_invokeId(asn1, subtree);
+
+ dissect_map_lnkId(asn1, subtree);
+
+ if (dissect_map_opr_code(asn1, pinfo, subtree, &op_idx) == MAP_OK)
+ {
+ /*
+ * decode elements
+ */
+ if (op_fcn[op_idx] == NULL)
+ {
+ dissect_map_params(asn1, subtree);
+ }
+ else
+ {
+ (*op_fcn[op_idx])(asn1, subtree);
+ }
+ }
+
+ if (!def_len)
+ {
+ dissect_map_eoc(asn1, subtree);
+ }
+}
+
+
+static void
+dissect_map_rr(ASN1_SCK *asn1, packet_info *pinfo, proto_tree *tree, gchar *str)
+{
+ guint tag, len, comp_len;
+ gint op_idx;
+ guint saved_offset;
+ proto_item *item, *null_item;
+ proto_tree *subtree;
+ gboolean def_len;
+ gboolean comp_def_len;
+
+ tag = -1;
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &tag);
+
+ item = proto_tree_add_text(tree, asn1->tvb, saved_offset, -1, "Components");
+
+ subtree = proto_item_add_subtree(item, ett_components);
+
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
+ saved_offset, asn1->offset - saved_offset, tag, str);
+
+ dissect_map_len(asn1, subtree, &comp_def_len, &comp_len);
+
+ if (comp_def_len)
+ {
+ proto_item_set_len(item, (asn1->offset - saved_offset) + comp_len);
+ }
+
+ dissect_map_invokeId(asn1, subtree);
+
+ if (check_map_tag(asn1, MAP_SEQ_TAG))
+ {
+ tag = -1;
+ dissect_map_tag(asn1, subtree, &tag, "Sequence Tag", &null_item);
+ dissect_map_len(asn1, subtree, &def_len, &len);
+ }
+
+ if (dissect_map_opr_code(asn1, pinfo, subtree, &op_idx) == MAP_OK)
+ {
+ dissect_map_params(asn1, subtree);
+ }
+
+ if (!comp_def_len)
+ {
+ dissect_map_eoc(asn1, subtree);
+ }
+}
+
+
+static int
+dissect_map_re(ASN1_SCK *asn1, proto_tree *tree)
+{
+ guint tag, len, comp_len;
+ guint saved_offset;
+ proto_item *item, *null_item;
+ proto_tree *subtree;
+ gboolean def_len;
+
+ tag = -1;
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &tag);
+
+ item = proto_tree_add_text(tree, asn1->tvb, saved_offset, -1, "Components");
+
+ subtree = proto_item_add_subtree(item, ett_components);
+
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
+ tag, "Return Error Type Tag");
+
+ dissect_map_len(asn1, subtree, &def_len, &comp_len);
+
+ if (def_len)
+ {
+ proto_item_set_len(item, (asn1->offset - saved_offset) + comp_len);
+ }
+
+ saved_offset = asn1->offset;
+ dissect_map_invokeId(asn1, subtree);
+
+#define MAP_LOCAL_ERR_CODE_TAG 0x2
+#define MAP_GBL_ERR_CODE_TAG 0x6
+ if (check_map_tag(asn1, MAP_LOCAL_ERR_CODE_TAG))
+ {
+ tag = -1;
+ dissect_map_tag(asn1, subtree, &tag, "Local Error Code Tag", &null_item);
+ }
+ else if (check_map_tag(asn1, MAP_GBL_ERR_CODE_TAG))
+ {
+ tag = -1;
+ dissect_map_tag(asn1, subtree, &tag, "Global Error Code Tag", &null_item);
+ }
+ else
+ {
+ proto_tree_add_text(subtree, asn1->tvb, asn1->offset, comp_len,
+ "Unknown Error Code");
+
+ asn1->offset += (comp_len - (asn1->offset - saved_offset));
+ return(MAP_OK);
+ }
+
+ dissect_map_len(asn1, subtree, &def_len, &len);
+ dissect_map_integer(asn1, subtree, len, "Error Code:");
+
+ dissect_map_params(asn1, subtree);
+
+ if (!def_len)
+ {
+ dissect_map_eoc(asn1, subtree);
+ }
+
+ return(MAP_OK);
+}
+
+
+static void
+dissect_map_reject(ASN1_SCK *asn1, proto_tree *tree)
+{
+ guint tag, len;
+ guint saved_offset;
+ proto_item *item;
+ proto_tree *subtree;
+ gboolean def_len;
+
+ tag = -1;
+
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &tag);
+
+ item = proto_tree_add_text(tree, asn1->tvb, saved_offset, -1, "Components");
+
+ subtree = proto_item_add_subtree(item, ett_components);
+
+ proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
+ tag, "Reject Type Tag");
+
+ dissect_map_len(asn1, subtree, &def_len, &len);
+
+ if (def_len)
+ {
+ proto_item_set_len(item, (asn1->offset - saved_offset) + len);
+ }
+
+ dissect_map_invokeId(asn1, subtree);
+ dissect_map_problem(asn1, subtree);
+
+ if (!def_len)
+ {
+ dissect_map_eoc(asn1, subtree);
+ }
+}
+
+
+static void
+dissect_map_message(packet_info *pinfo, proto_tree *map_tree, ASN1_SCK *asn1)
+{
+ guint tag;
+ guint saved_offset;
+ gchar *str = NULL;
+ static int i = 0;
+
+ saved_offset = asn1->offset;
+ asn1_id_decode1(asn1, &tag);
+ asn1->offset = saved_offset;
+
+ str = match_strval(tag, tag_strings);
+
+ if (NULL == str) return;
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ {
+ if (0 == i)
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", str);
+ }
+ else
+ {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "& %s ", str);
+ }
+ }
+
+ switch(tag)
+ {
+ case MAP_TC_INVOKE :
+ dissect_map_invoke(asn1, pinfo, map_tree);
+ break;
+
+ case MAP_TC_RRL :
+ dissect_map_rr(asn1, pinfo, map_tree, "Return Result(Last) Type Tag");
+ break;
+
+ case MAP_TC_RE :
+ dissect_map_re(asn1, map_tree);
+ break;
+
+ case MAP_TC_REJECT :
+ dissect_map_reject(asn1, map_tree);
+ break;
+
+ case MAP_TC_RRN :
+ dissect_map_rr(asn1, pinfo, map_tree, "Return Result(Not Last) Type Tag");
+ break;
+
+ default:
+ proto_tree_add_text(map_tree, asn1->tvb, saved_offset, -1,
+ "Message type not handled, ignoring");
+ break;
+ }
+}
+
+
+static void
+dissect_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ti;
+ proto_tree *map_tree;
+ ASN1_SCK asn1;
+ int offset = 0;
+
+ /*
+ * Make entries in Protocol column on summary display
+ */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ {
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "GSM MAP");
+ }
+
+
+ /* In the interest of speed, if "tree" is NULL, don't do any work not
+ * necessary to generate protocol tree items.
+ */
+ if (tree)
+ {
+ /* create display subtree for the protocol */
+ ti = proto_tree_add_item(tree, proto_map, tvb, 0, -1, FALSE);
+
+ map_tree = proto_item_add_subtree(ti, ett_map);
+
+ asn1_open(&asn1, tvb, offset);
+
+ dissect_map_message(pinfo, map_tree, &asn1);
+
+ asn1_close(&asn1, &offset);
+ }
+}
+
+
+/* Register the protocol with Ethereal */
+
+void
+proto_register_map(void)
+{
+ guint i;
+ gint last_offset;
+
+ /* Setup list of header fields See Section 1.6.1 for details*/
+ static hf_register_info hf[] =
+ {
+ { &hf_map_tag,
+ { "Tag", "map.msgtype",
+ FT_UINT8, BASE_HEX, NULL, 0,
+ "", HFILL }
+ },
+ { &hf_map_length,
+ { "Length", "map.len",
+ FT_UINT8, BASE_HEX, NULL, 0,
+ "", HFILL }
+ },
+ { &hf_map_opr_code,
+ { "Operation Code", "map.oprcode",
+ FT_INT32, BASE_DEC, VALS(opr_code_strings), 0,
+ "", HFILL }
+ },
+ { &hf_map_int,
+ { "Integer Data", "map.data",
+ FT_INT32, BASE_DEC, 0, 0,
+ "", HFILL }
+ },
+ };
+
+ /* Setup protocol subtree array */
+#define NUM_INDIVIDUAL_PARAMS 7
+ static gint *ett[NUM_INDIVIDUAL_PARAMS+GSM_MAP_NUM_OP+NUM_PARAM_1];
+
+ memset((void *) ett, 0, sizeof(ett));
+
+ ett[0] = &ett_map;
+ ett[1] = &ett_opr_code;
+ ett[2] = &ett_component;
+ ett[3] = &ett_components;
+ ett[4] = &ett_param;
+ ett[5] = &ett_params;
+ ett[6] = &ett_problem;
+
+ last_offset = NUM_INDIVIDUAL_PARAMS;
+
+ for (i=0; i < GSM_MAP_NUM_OP; i++, last_offset++)
+ {
+ ett_op[i] = -1;
+ ett[last_offset] = &ett_op[i];
+ }
+
+ for (i=0; i < NUM_PARAM_1; i++, last_offset++)
+ {
+ ett_param_1[i] = -1;
+ ett[last_offset] = &ett_param_1[i];
+ }
+
+ /* Register the protocol name and description */
+ proto_map =
+ proto_register_protocol("GSM Mobile Application Part",
+ "GSM MAP", "gsm_map");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_map, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_map(void)
+{
+ dissector_handle_t map_handle;
+
+ map_handle = create_dissector_handle(dissect_map, proto_map);
+ dissector_add("tcap.itu_ssn", 6, map_handle);
+ dissector_add("tcap.itu_ssn", 7, map_handle);
+ dissector_add("tcap.itu_ssn", 8, map_handle);
+ dissector_add("tcap.itu_ssn", 9, map_handle);
+}