The current year is 2004
[obnox/wireshark/wip.git] / packet-gsm_map.c
1 /* packet-gsm_map.c
2  * Routines for GSM Mobile Application Part dissection
3  *
4  * Copyright 2000, Felix Fei <felix.fei [AT] utstar.com>
5  *
6  * Michael Lum <mlum [AT] telostech.com>,
7  * Changed to run on new version of TCAP, many changes for
8  * EOC matching, and parameter separation.  (2003)
9  *
10  * $Id: packet-gsm_map.c,v 1.4 2003/12/21 21:41:10 guy Exp $
11  *
12  * Ethereal - Network traffic analyzer
13  * By Gerald Combs <gerald@ethereal.com>
14  * Copyright 1998 Gerald Combs
15  *
16  * Copied from packet-tcap.c (where "WHATEVER_FILE_YOU_USED"
17  * is a dissector file; if you just copied this from README.developer,
18  * don't bother with the "Copied from" - you don't even need to put
19  * in a "Copied from" if you copied an existing dissector, especially
20  * if the bulk of the code in the new dissector is your code)
21  *
22  * This program is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU General Public License
24  * as published by the Free Software Foundation; either version 2
25  * of the License, or (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35  */
36
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "epan/packet.h"
46 #include "asn1.h"
47
48
49 /* OPERATION CODE DEFINITION */
50
51 /* LOCATION MANAGEMENT */
52 #define MAP_UPD_LOC                     2       /* Update Location */
53 #define MAP_CANCEL_LOC                  3       /* Cancel Location */
54 #define MAP_PURGE                       67      /* Purge MS */
55 #define MAP_SEND_ID                     5       /* Send Identification */
56 #define MAP_GPRS_UPD_LOC                23      /* GPRS Update Location */
57 #define MAP_DET_IMSI                    5       /* Detach IMSI */
58 #define MAP_NOTE_MM_EVT                 89      /* Note MM Event */
59
60 /* HANDOVER MANAGEMENT */
61 #define MAP_PREP_HO                     68      /* Prepare Handover */
62 #define MAP_PREP_SUBS_HO                69      /* Prepare Subsequent Handover */
63 #define MAP_PERF_HO                     28      /* Perform Handover */
64 #define MAP_PERF_SUBS_HO                30      /* Perform Subsequent Handover */
65 #define MAP_SEND_END_SIG                29      /* Send End Signal */
66 #define MAP_PROC_ACC_SIG                33      /* Process Access Signalling */
67 #define MAP_FWD_ACC_SIG                 34      /* Forward Access Signalling */
68
69 /* AUTHENTICATION MANAGEMENT */
70 #define MAP_AUTH_INFO                   56      /* Send Authintication Info */
71 #define MAP_AUTH_FAIL_RPT               15      /* Authentication Failure Report */
72
73 /*  IDENTIFICATION MANAGEMENT */
74 #define MAP_CHK_IMEI                    43      /* Check IMEI */
75
76 /* FAULT & RECOVERY MANAGEMENT */
77 #define MAP_RESET                       37      /* Reset */
78 #define MAP_RESTORE_DATA                57      /* Restore Data */
79 #define MAP_FWD_CHK_SS_IND              38      /* Forward Check SS Indication */
80
81 /* OAM MANAGEMENT */
82 #define MAP_ACT_TRACE                   50      /* Activate Trace */
83 #define MAP_DEACT_TRACE                 51      /* Deactivate Trace Mode */
84 #define MAP_SEND_IMSI                   58      /* Send IMSI */
85 #define MAP_TRACE_SUBS_ACTV             52      /* Trace Subscriber Activity */
86 #define MAP_NOTE_INTER_HO               35      /* Not Internal Handover */
87
88 /* CALL MANAGEMENT */
89 #define MAP_ROUTE_INFO                  22      /* Send Routing Info */
90 #define MAP_PROV_ROAM_NUM               4       /* Provide Roaming Number */
91 #define MAP_PROV_SIWFS_NUM              31      /* Provide SIWFS Number */
92 #define MAP_SIWFS_SIG_MOD               32      /* SIWFS Signalling Modify */
93 #define MAP_RES_CALL_HAND               6       /* Resume Call Handling */
94 #define MAP_SET_RPT_STATE               73      /* Set Reporting State */
95 #define MAP_STAT_RPT                    74      /* Status Report */
96 #define MAP_REM_USR_FREE                75      /* Remote user free */
97 #define MAP_PREP_GRP_CALL               39      /* Prepare Group Call */
98 #define MAP_SND_GRP_CALL_END_SIG        40      /* Send Group Call End Signalling */
99 #define MAP_PRO_GRP_CALL_SIG            41      /* Process Group Call Signalling  */
100 #define MAP_FWD_GRP_CALL_SIG            42      /* Forward Group Call Signalling  */
101 #define MAP_IST_ALERT                   87      /* IST Alert */
102 #define MAP_IST_COMMAND                 88      /* IST Command */
103
104 /* SS MANAGEMENT */
105 #define MAP_REG_SS                      10      /* Register SS */
106 #define MAP_ERASE_SS                    11      /* Erase SS */
107 #define MAP_ACT_SS                      12      /* Activate SS */
108 #define MAP_DEACT_SS                    13      /* Deactivate SS */
109 #define MAP_INTER_SS                    14      /* Interogate SS */
110 #define MAP_PROC_U_SS_REQ               59      /* Process Unstructured SS Req */
111 #define MAP_U_SS_REQ                    60      /* Unstructured SS Request */
112 #define MAP_U_SS_NOTIFY                 61      /* Unstructured SS Notify */
113 #define MAP_REG_PASSWD                  17      /* Register Password */
114 #define MAP_GET_PASSWD                  18      /* Get Password */
115 #define MAP_REG_CC_ENT                  76      /* Register CC Entry */
116 #define MAP_ERASE_CC_ENT                77      /* Erase CC Entry */
117 #define MAP_BEGIN_SUBS_ACTV             54      /* Begin Subscriber Activity */
118 #define MAP_PROC_U_SS_DATA              19      /* Process Unstructured SS Data */
119 #define MAP_SS_INV_NOTIFY               72      /* SS Invocation Notify */
120
121 /* SMS MANAGEMENT */
122 #define MAP_MO_FWD_SM                   46      /* Forward Short Message */
123 #define MAP_MT_FWD_SM                   44      /* MT-Fwd SM */
124 #define MAP_ROUTE_INFO_SM               45      /* Routing Info for SM */
125 #define MAP_SM_DEL_STAT                 47      /* Report SM Delivery Status */
126 #define MAP_INFORM_SC                   63      /* Inform Service Center */
127 #define MAP_ALERT_SC                    64      /* Alert Service Center */
128 #define MAP_SM_READY                    66      /* SM Ready */
129 #define MAP_NOTE_SUB_PRES               48      /* Note Subscriber Present */
130 #define MAP_ALERT_SC_W_RES              49      /* Alert SC Without Result */
131
132 /* SUBSCRIBER MANAGEMENT */
133 #define MAP_INS_SUB_DATA                7       /* Insert Subscriber Data */
134 #define MAP_DEL_SUB_DATA                8       /* Delete Subscriber Data */
135 #define MAP_PROV_SUB_INFO               70      /* Provide Subscriber Info */
136 #define MAP_ANY_TIME_INTER              71      /* Any Time Interrogation */
137 #define MAP_SEND_PARAM                  9       /* Send Parameters */
138 #define MAP_ANY_TIME_SUB_DATA_INTER     62      /* Any Time Subscriber Info Interrogation */
139 #define MAP_ANY_TIME_MOD                65      /* Any Time Modification */
140 #define MAP_NOTE_SUB_DATA_MOD           5       /* Note Subscriber Data Modified */
141
142 /* PDP ACTIVE MANAGEMENT */
143 #define MAP_GPRS_ROUTE_INFO             24      /* Rout Info for GPRS */
144 #define MAP_FAIL_REP                    25      /* Failure Report */
145 #define MAP_GPRS_NOTE_MS_PRES           26      /* GPRS NoteMs Present */
146
147 /* LOCATION SERVICE */
148 #define MAP_PROV_SUB_LOC                83      /* Provide Subscriber Location */
149 #define MAP_SEND_ROUTE_INFO_FOR_LCS     85      /* Send Routing Info For LCS */
150 #define MAP_SUB_LOC_REP                 86      /* Subscriber Location Report */
151
152
153 #define MAP_OPR_CODE_TAG        0x02
154 #define MAP_INVOKE_ID_TAG       0x02
155 #define MAP_LINK_ID_TAG         0x80
156 #define MAP_SEQ_TAG             0x30
157 #define MAP_GE_PROBLEM_TAG      0x80
158 #define MAP_IN_PROBLEM_TAG      0x81
159 #define MAP_RR_PROBLEM_TAG      0x82
160 #define MAP_RE_PROBLEM_TAG      0x83
161 #define MAP_INVALID_TAG         0x00
162
163 #define MAP_OK                  0x0
164 #define MAP_FAIL                0x1
165
166 static const value_string opr_code_strings[] = {
167
168 /* LOCATION MANAGEMENT */
169     { MAP_UPD_LOC,                      "Update Location"},
170     { MAP_CANCEL_LOC,                   "Cancel Location"},
171     { MAP_PURGE,                        "Purge MS"},
172     { MAP_SEND_ID,                      "Send Identification"},
173     { MAP_GPRS_UPD_LOC,                 "Update GPRS Location"},
174     { MAP_DET_IMSI,                     "Detach IMSI"},
175     { MAP_NOTE_MM_EVT,                  "Note MM Event"},
176
177 /* HANDOVER MANAGEMENT */
178     { MAP_PREP_HO,                      "Prepare Handover"},
179     { MAP_PREP_SUBS_HO,                 "Prepare Subsequent Handover"},
180     { MAP_PERF_HO,                      "Perform Handover"},
181     { MAP_PERF_SUBS_HO,                 "Perform Subsequent Handover"},
182     { MAP_SEND_END_SIG,                 "Send End Signal"},
183     { MAP_PROC_ACC_SIG,                 "Process Access Signalling"},
184     { MAP_FWD_ACC_SIG,                  "Forward Access Signalling"},
185
186 /* AUTHENTICATION MANAGEMENT */
187     { MAP_AUTH_INFO,                    "Send Authentication Info"},
188     { MAP_AUTH_FAIL_RPT,                "Authentication Failure Report"},
189
190 /* IDENTIFICATION MANAGEMENT */
191     { MAP_CHK_IMEI,                     "Check IMEI"},
192
193 /* FAULT & RECOVERY MANAGEMENT */
194     { MAP_RESET,                        "Reset"},
195     { MAP_RESTORE_DATA,                 "Restore Data"},
196     { MAP_FWD_CHK_SS_IND,               "Forward Check SS Indication"},
197
198 /* OAM MANAGEMENT */
199     { MAP_ACT_TRACE,                    "Activate Trace Mode"},
200     { MAP_DEACT_TRACE,                  "Deactivate Trace Mode"},
201     { MAP_SEND_IMSI,                    "Send IMSI"},
202     { MAP_TRACE_SUBS_ACTV,              "Trace Subscriber Activity"},
203     { MAP_NOTE_INTER_HO,                "Note Internal Handover"},
204
205 /*  CALL MANAGEMENT */
206     { MAP_ROUTE_INFO,                   "Send Routing Info"},
207     { MAP_PROV_ROAM_NUM,                "Provide Roaming Number"},
208     { MAP_PROV_SIWFS_NUM,               "Provide SIWFS Number"},
209     { MAP_SIWFS_SIG_MOD,                "SIWFS Signalling Modify"},
210     { MAP_RES_CALL_HAND,                "Resume Call Handling"},
211     { MAP_SET_RPT_STATE,                "Set Reporting State"},
212     { MAP_STAT_RPT,                     "Status Report"},
213     { MAP_REM_USR_FREE,                 "Remote User Free"},
214     { MAP_PREP_GRP_CALL,                "Prepare Group Call"},
215     { MAP_SND_GRP_CALL_END_SIG,         "Send Group Call End Signalling"},
216     { MAP_PRO_GRP_CALL_SIG,             "Process Group Call Signalling"},
217     { MAP_FWD_GRP_CALL_SIG,             "Forward Group Call Signalling"},
218     { MAP_IST_ALERT,                    "IST Alert"},
219     { MAP_IST_COMMAND,                  "IST Command"},
220
221 /* SS MANAGEMENT */
222     { MAP_REG_SS,                       "Register SS"},
223     { MAP_ERASE_SS,                     "Erase SS"},
224     { MAP_ACT_SS,                       "Activate SS"},
225     { MAP_DEACT_SS,                     "Deactivate SS"},
226     { MAP_INTER_SS,                     "Interogate SS"},
227     { MAP_PROC_U_SS_REQ,                "Process Unstructured SS Request"},
228     { MAP_U_SS_REQ,                     "Unstructured SS Request"},
229     { MAP_U_SS_NOTIFY,                  "Unstructured SS Notify"},
230     { MAP_REG_PASSWD,                   "Register Password"},
231     { MAP_GET_PASSWD,                   "Get Password"},
232     { MAP_REG_CC_ENT,                   "Register CC Entry"},
233     { MAP_ERASE_CC_ENT,                 "Erase CC Entry"},
234     { MAP_BEGIN_SUBS_ACTV,              "Begin Subscriber Activity"},
235     { MAP_PROC_U_SS_DATA,               "Process Unstructured SS Data"},
236     { MAP_SS_INV_NOTIFY,                "SS Invocation Notification"},
237
238 /* SMS MANAGEMENT */
239     { MAP_MO_FWD_SM,                    "MO Forward SM"},
240     { MAP_MT_FWD_SM,                    "MT Forward SM"},
241     { MAP_ROUTE_INFO_SM,                "Send Routing Info For SM"},
242     { MAP_SM_DEL_STAT,                  "Report SM Delivery Status"},
243     { MAP_INFORM_SC,                    "Inform Service Center"},
244     { MAP_ALERT_SC,                     "Alert Service Center"},
245     { MAP_SM_READY,                     "Ready For SM"},
246     { MAP_NOTE_SUB_PRES,                "Note Subscriber Present"},
247     { MAP_ALERT_SC_W_RES,               "Alert SC Without Result"},
248
249 /* SUBSCRIBER MANAGEMENT */
250     { MAP_INS_SUB_DATA,                 "Insert Subscriber Data"},
251     { MAP_DEL_SUB_DATA,                 "Delete Subscriber Data"},
252     { MAP_PROV_SUB_INFO,                "Provide Subscriber Info"},
253     { MAP_ANY_TIME_INTER,               "Any Time Interrogation"},
254     { MAP_SEND_PARAM,                   "Send Parameters"},
255     { MAP_ANY_TIME_SUB_DATA_INTER,      "Any Time Subscription Interrogation"},
256     { MAP_ANY_TIME_MOD,                 "Any Time Modification"},
257     { MAP_NOTE_SUB_DATA_MOD,            "Note Subscriber Data Modified"},
258
259 /* PDP ACTIVE MANAGEMENT */
260     { MAP_GPRS_ROUTE_INFO,              "Send Routing Info For GPRS"},
261     { MAP_FAIL_REP,                     "Failure Report"},
262     { MAP_GPRS_NOTE_MS_PRES,            "Note MS Present For GPRS"},
263
264 /* LOCATION SERVICE */
265     { MAP_PROV_SUB_LOC,                 "Provide Subscriber Location"},
266     { MAP_SEND_ROUTE_INFO_FOR_LCS,      "Send Routing Info For LCS"},
267     { MAP_SUB_LOC_REP,                  "Subscriber Location Report"},
268
269     { 0,                                NULL},
270 };
271
272 /* TCAP component type */
273 #define MAP_TC_INVOKE           0xa1
274 #define MAP_TC_RRL              0xa2
275 #define MAP_TC_RE               0xa3
276 #define MAP_TC_REJECT           0xa4
277 #define MAP_TC_RRN              0xa7
278
279 static const value_string tag_strings[] = {
280     { MAP_TC_INVOKE,            "Invoke" },
281     { MAP_TC_RRL,               "RetRes(Last)" },
282     { MAP_TC_RE,                "RetErr" },
283     { MAP_TC_REJECT,            "Reject" },
284     { MAP_TC_RRN,               "RetRes(Not Last)" },
285     { 0,                        NULL},
286 };
287
288 /* Initialize the protocol and registered fields */
289 static int proto_map = -1;
290 static int hf_map_tag = -1;
291 static int hf_map_length = -1;
292 static int hf_map_opr_code = -1;
293 static int hf_map_int = -1;
294
295 /* Initialize the subtree pointers */
296 static gint ett_map = -1;
297 static gint ett_component = -1;
298 static gint ett_components = -1;
299 static gint ett_param = -1;
300 static gint ett_params = -1;
301 static gint ett_problem = -1;
302 static gint ett_opr_code = -1;
303
304 static const value_string param_1_strings[] = {
305     { 0x04,     "IMSI" },
306     { 0x81,     "msc-Number" },
307     { 0,        NULL },
308 };
309
310
311 typedef struct dgt_set_t
312 {
313     unsigned char out[15];
314 }
315 dgt_set_t;
316
317 static dgt_set_t Dgt_tbcd = {
318     {
319   /*  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e */
320      '0','1','2','3','4','5','6','7','8','9','?','B','C','*','#'
321     }
322 };
323
324 static dgt_set_t Dgt_msid = {
325     {
326   /*  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e */
327      '0','1','2','3','4','5','6','7','8','9','?','?','?','?','?'
328     }
329 };
330
331
332 /* FUNCTIONS */
333
334 /*
335  * Unpack BCD input pattern into output ASCII pattern
336  *
337  * Input Pattern is supplied using the same format as the digits
338  *
339  * Returns: length of unpacked pattern
340  */
341 static int
342 my_dgt_tbcd_unpack(
343     char        *out,           /* ASCII pattern out */
344     guchar      *in,            /* packed pattern in */
345     int         num_octs,       /* Number of octets to unpack */
346     dgt_set_t   *dgt            /* Digit definitions */
347     )
348 {
349     int cnt = 0;
350     unsigned char i;
351
352     while (num_octs)
353     {
354         /*
355          * unpack first value in byte
356          */
357         i = *in++;
358         *out++ = dgt->out[i & 0x0f];
359         cnt++;
360
361         /*
362          * unpack second value in byte
363          */
364         i >>= 4;
365
366         if (i == 0x0f)  /* odd number bytes - hit filler */
367             break;
368
369         *out++ = dgt->out[i];
370         cnt++;
371         num_octs--;
372     }
373
374     *out = '\0';
375
376     return(cnt);
377 }
378
379 static gchar *
380 my_match_strval(guint32 val, const value_string *vs, gint *idx)
381 {
382     gint        i = 0;
383
384     while (vs[i].strptr) {
385         if (vs[i].value == val)
386         {
387             *idx = i;
388             return(vs[i].strptr);
389         }
390
391         i++;
392     }
393
394     *idx = -1;
395     return(NULL);
396 }
397
398
399 static gboolean
400 check_map_tag(ASN1_SCK *asn1, guint tag)
401 {
402     guint       saved_offset, real_tag;
403
404     if (tvb_length_remaining(asn1->tvb, asn1->offset) <= 0)
405     {
406         return(FALSE);
407     }
408
409     saved_offset = asn1->offset;
410     asn1_id_decode1(asn1, &real_tag);
411     asn1->offset = saved_offset;
412
413     return(tag == real_tag);
414 }
415
416 /* PARAMETERS */
417
418 static void
419 param_imsi(ASN1_SCK *asn1, proto_tree *tree, guint len)
420 {
421     guint       saved_offset;
422     guchar      *poctets;
423     char        bigbuf[1024];
424
425     saved_offset = asn1->offset;
426     asn1_string_value_decode(asn1, len, &poctets);
427
428     my_dgt_tbcd_unpack(bigbuf, poctets, len, &Dgt_msid);
429
430     proto_tree_add_text(tree, asn1->tvb,
431         saved_offset, len, "IMSI %s", bigbuf);
432 }
433
434 static void
435 param_AddressString(ASN1_SCK *asn1, proto_tree *tree, guint len)
436 {
437     guint       saved_offset;
438     gint32      value;
439     guchar      *poctets;
440     gchar       *str = NULL;
441     char        bigbuf[1024];
442
443     saved_offset = asn1->offset;
444     asn1_int32_value_decode(asn1, 1, &value);
445
446     other_decode_bitfield_value(bigbuf, value, 0x80, 8);
447     proto_tree_add_text(tree, asn1->tvb,
448         saved_offset, 1,
449         "%s :  %sxtension",
450         bigbuf, (value & 0x80) ? "No E" : "E");
451
452     switch ((value & 0x70) >> 4)
453     {
454     case 0x00: str = "unknown"; break;
455     case 0x01: str = "International Number"; break;
456     case 0x02: str = "National Significant Number"; break;
457     case 0x03: str = "Network Specific Number"; break;
458     case 0x04: str = "Subscriber Number"; break;
459     case 0x05: str = "Reserved"; break;
460     case 0x06: str = "Abbreviated Number"; break;
461     case 0x07: str = "Reserved for extension"; break;
462     }
463
464     other_decode_bitfield_value(bigbuf, value, 0x70, 8);
465     proto_tree_add_text(tree, asn1->tvb,
466         saved_offset, asn1->offset - saved_offset,
467         "%s :  %s",
468         bigbuf, str);
469
470     switch (value & 0x0f)
471     {
472     case 0x00: str = "unknown"; break;
473     case 0x01: str = "ISDN/Telephony Numbering (Rec ITU-T E.164)"; break;
474     case 0x02: str = "spare"; break;
475     case 0x03: str = "Data Numbering (ITU-T Rec. X.121)"; break;
476     case 0x04: str = "Telex Numbering (ITU-T Rec. F.69)"; break;
477     case 0x05: str = "spare"; break;
478     case 0x06: str = "Land Mobile Numbering (ITU-T Rec. E.212)"; break;
479     case 0x07: str = "spare"; break;
480     case 0x08: str = "National Numbering"; break;
481     case 0x09: str = "Private Numbering"; break;
482     case 0x0f: str = "Reserved for extension"; break;
483     default:
484         str = "Reserved";
485         break;
486     }
487
488     other_decode_bitfield_value(bigbuf, value, 0x0f, 8);
489     proto_tree_add_text(tree, asn1->tvb,
490         saved_offset, asn1->offset - saved_offset,
491         "%s :  %s",
492         bigbuf, str);
493
494     saved_offset = asn1->offset;
495     asn1_string_value_decode(asn1, len - 1, &poctets);
496
497     my_dgt_tbcd_unpack(bigbuf, poctets, len - 1, &Dgt_msid);
498
499     proto_tree_add_text(tree, asn1->tvb, saved_offset, len - 1,
500         "BCD Digits %s", bigbuf);
501 }
502
503 #define NUM_PARAM_1 (sizeof(param_1_strings)/sizeof(value_string))
504 static gint ett_param_1[NUM_PARAM_1];
505 static void (*param_1_fcn[])(ASN1_SCK *asn1, proto_tree *tree, guint len) = {
506     param_imsi,                 /* IMSI */
507     param_AddressString,        /* msc-Number */
508     NULL,                       /* NONE */
509 };
510
511
512 /* MESSAGES */
513
514 static void
515 op_send_auth_info(ASN1_SCK *asn1, proto_tree *tree)
516 {
517     void        (*param_fcn)(ASN1_SCK *asn1, proto_tree *tree, guint len) = NULL;
518     guint       off_tree[100], saved_offset, len_offset;
519     int         num_seq;
520     guint       tag, len;
521     gboolean    def_len = FALSE;
522     proto_item  *item_tree[100], *item;
523     proto_tree  *seq_tree[100], *use_tree, *subtree;
524     gchar       *str = NULL;
525     gint        ett_param_idx, idx;
526
527     num_seq = 0;
528     use_tree = tree;
529
530     while ((tvb_length_remaining(asn1->tvb, asn1->offset) > 0) &&
531         (!check_map_tag(asn1, 0)))
532     {
533         saved_offset = asn1->offset;
534         asn1_id_decode1(asn1, &tag);
535         len_offset = asn1->offset;
536         asn1_length_decode(asn1, &def_len, &len);
537
538         if (tag == MAP_SEQ_TAG)
539         {
540             item =
541                 proto_tree_add_text(use_tree, asn1->tvb,
542                     saved_offset, -1, "Sequence");
543
544             subtree = proto_item_add_subtree(item, ett_params);
545
546             proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
547                 saved_offset, len_offset - saved_offset, tag, "Sequence Tag");
548
549             if (!def_len)
550             {
551                 proto_tree_add_text(subtree, asn1->tvb,
552                     len_offset, asn1->offset - len_offset, "Length: Indefinite");
553
554                 seq_tree[num_seq] = subtree;
555                 item_tree[num_seq] = item;
556                 off_tree[num_seq] = saved_offset;
557                 num_seq++;
558             }
559             else
560             {
561                 proto_tree_add_uint(subtree, hf_map_length, asn1->tvb,
562                     len_offset, asn1->offset - len_offset, len);
563
564                 proto_item_set_len(item, (asn1->offset - saved_offset) + len);
565             }
566
567             use_tree = subtree;
568             continue;
569         }
570
571         if (!def_len)
572         {
573             proto_tree_add_uint_format(use_tree, hf_map_tag, asn1->tvb,
574                 saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
575             proto_tree_add_text(use_tree, asn1->tvb,
576                 len_offset, asn1->offset - len_offset, "Length: Indefinite");
577
578             seq_tree[num_seq] = use_tree;
579             item_tree[num_seq] = NULL;
580             num_seq++;
581             continue;
582         }
583         else
584         {
585 #ifdef MLUM
586             /*
587              * XXX
588              * how do you recognize the correct parameters here ?
589              */
590             str = my_match_strval((guint32) tag, param_1_strings, &idx);
591 #else
592             str = NULL;
593             idx = 0;
594 #endif
595
596             if (str == NULL)
597             {
598                 str = "Parameter";
599                 ett_param_idx = ett_param;
600                 param_fcn = NULL;
601             }
602             else
603             {
604                 ett_param_idx = ett_param_1[idx];
605                 param_fcn = param_1_fcn[idx];
606             }
607
608             item =
609                 proto_tree_add_text(use_tree, asn1->tvb,
610                     saved_offset, -1, str);
611
612             subtree = proto_item_add_subtree(item, ett_param_idx);
613
614             proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
615                 saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
616
617             proto_tree_add_uint(subtree, hf_map_length, asn1->tvb,
618                 len_offset, asn1->offset - len_offset, len);
619
620             proto_item_set_len(item, (asn1->offset - saved_offset) + len);
621
622             if (param_fcn == NULL)
623             {
624                 proto_tree_add_text(subtree, asn1->tvb,
625                     asn1->offset, len, "Parameter Data");
626
627                 asn1->offset += len;
628             }
629             else
630             {
631                 (*param_fcn)(asn1, subtree, len);
632             }
633         }
634
635         if (tvb_length_remaining(asn1->tvb, asn1->offset) <=0) break;
636
637         while ((num_seq > 0) &&
638             asn1_eoc(asn1, -1))
639         {
640             saved_offset = asn1->offset;
641             asn1_eoc_decode(asn1, -1);
642
643             proto_tree_add_text(seq_tree[num_seq-1], asn1->tvb,
644                 saved_offset, asn1->offset - saved_offset, "End of Contents");
645
646             if (item_tree[num_seq-1] != NULL)
647             {
648                 proto_item_set_len(item_tree[num_seq-1], asn1->offset - off_tree[num_seq-1]);
649             }
650
651             num_seq--;
652         }
653     }
654 }
655
656 #define GSM_MAP_NUM_OP (sizeof(opr_code_strings)/sizeof(value_string))
657 static gint ett_op[GSM_MAP_NUM_OP];
658 static void (*op_fcn[])(ASN1_SCK *asn1, proto_tree *tree) = {
659     NULL,       /* Update Location */
660     NULL,       /* Cancel Location */
661     NULL,       /* Purge MS */
662     NULL,       /* Send Identification */
663     NULL,       /* Update GPRS Location */
664     NULL,       /* Detach IMSI */
665     NULL,       /* Note MM Event */
666     NULL,       /* Prepare Handover */
667     NULL,       /* Prepare Subsequent Handover */
668     NULL,       /* Perform Handover */
669     NULL,       /* Perform Subsequent Handover */
670     NULL,       /* Send End Signal */
671     NULL,       /* Process Access Signalling */
672     NULL,       /* Forward Access Signalling */
673     op_send_auth_info,  /* Send Authentication Info */
674     NULL,       /* Authentication Failure Report */
675     NULL,       /* Check IMEI */
676     NULL,       /* Reset */
677     NULL,       /* Restore Data */
678     NULL,       /* Forward Check SS Indication */
679     NULL,       /* Activate Trace Mode */
680     NULL,       /* Deactivate Trace Mode */
681     NULL,       /* Send IMSI */
682     NULL,       /* Trace Subscriber Activity */
683     NULL,       /* Note Internal Handover */
684     NULL,       /* Send Routing Info */
685     NULL,       /* Provide Roaming Number */
686     NULL,       /* Provide SIWFS Number */
687     NULL,       /* SIWFS Signalling Modify */
688     NULL,       /* Resume Call Handling */
689     NULL,       /* Set Reporting State */
690     NULL,       /* Status Report */
691     NULL,       /* Remote User Free */
692     NULL,       /* Prepare Group Call */
693     NULL,       /* Send Group Call End Signalling */
694     NULL,       /* Process Group Call Signalling */
695     NULL,       /* Forward Group Call Signalling */
696     NULL,       /* IST Alert */
697     NULL,       /* IST Command */
698     NULL,       /* Register SS */
699     NULL,       /* Erase SS */
700     NULL,       /* Activate SS */
701     NULL,       /* Deactivate SS */
702     NULL,       /* Interogate SS */
703     NULL,       /* Process Unstructured SS Request */
704     NULL,       /* Unstructured SS Request */
705     NULL,       /* Unstructured SS Notify */
706     NULL,       /* Register Password */
707     NULL,       /* Get Password */
708     NULL,       /* Register CC Entry */
709     NULL,       /* Erase CC Entry */
710     NULL,       /* Begin Subscriber Activity */
711     NULL,       /* Process Unstructured SS Data */
712     NULL,       /* SS Invocation Notification */
713     NULL,       /* MO Forward SM */
714     NULL,       /* MT Forward SM */
715     NULL,       /* Send Routing Info For SM */
716     NULL,       /* Report SM Delivery Status */
717     NULL,       /* Inform Service Center */
718     NULL,       /* Alert Service Center */
719     NULL,       /* Ready For SM */
720     NULL,       /* Note Subscriber Present */
721     NULL,       /* Alert SC Without Result */
722     NULL,       /* Insert Subscriber Data */
723     NULL,       /* Delete Subscriber Data */
724     NULL,       /* Provide Subscriber Info */
725     NULL,       /* Any Time Interrogation */
726     NULL,       /* Send Parameters */
727     NULL,       /* Any Time Subscription Interrogation */
728     NULL,       /* Any Time Modification */
729     NULL,       /* Note Subscriber Data Modified */
730     NULL,       /* Send Routing Info For GPRS */
731     NULL,       /* Failure Report */
732     NULL,       /* Note MS Present For GPRS */
733     NULL,       /* Provide Subscriber Location */
734     NULL,       /* Send Routing Info For LCS */
735     NULL,       /* Subscriber Location Report */
736
737     NULL,       /* NONE */
738 };
739
740
741 /* GENERIC MAP DISSECTOR FUNCTIONS */
742
743 static int
744 dissect_map_tag(ASN1_SCK *asn1, proto_tree *tree, guint *tag, guchar * str,
745     proto_item **item_p)
746 {
747     guint       saved_offset, real_tag;
748
749     saved_offset = asn1->offset;
750     asn1_id_decode1(asn1, &real_tag);
751     if ((*tag != (guint) -1) && (real_tag != *tag))
752     {
753         asn1->offset = saved_offset;
754         return(MAP_FAIL);
755     }
756
757     *item_p =
758         proto_tree_add_uint_format(tree, hf_map_tag, asn1->tvb,
759             saved_offset, asn1->offset - saved_offset,
760             real_tag, str);
761
762     return(MAP_OK);
763 }
764
765
766 static int
767 dissect_map_len(ASN1_SCK *asn1, proto_tree *tree, gboolean *def_len, guint *len)
768 {
769     guint       saved_offset;
770
771     saved_offset = asn1->offset;
772     *len = 0;
773     *def_len = FALSE;
774     asn1_length_decode(asn1, def_len, len);
775
776     if (*def_len)
777     {
778         proto_tree_add_uint(tree, hf_map_length, asn1->tvb, saved_offset,
779             asn1->offset - saved_offset, *len);
780     }
781     else
782     {
783         proto_tree_add_text(tree, asn1->tvb,
784             saved_offset, asn1->offset - saved_offset, "Length: Indefinite");
785     }
786
787     return(MAP_OK);
788 }
789
790
791 static int
792 dissect_map_integer(ASN1_SCK *asn1, proto_tree *tree, guint len, guchar * str)
793 {
794     guint       saved_offset;
795     gint32      invokeId;
796
797     saved_offset = asn1->offset;
798     asn1_int32_value_decode(asn1, len, &invokeId);
799
800     proto_tree_add_int_format(tree, hf_map_int, asn1->tvb,
801         saved_offset, asn1->offset - saved_offset,
802         invokeId, "%s %d", str, invokeId);
803
804     return(MAP_OK);
805 }
806
807
808 static int
809 dissect_map_invokeId(ASN1_SCK *asn1, proto_tree *tree)
810 {
811     guint       saved_offset = 0;
812     guint       len;
813     guint       tag;
814     proto_item  *item, *null_item;
815     proto_tree  *subtree;
816     gboolean    def_len;
817
818     if (check_map_tag(asn1, MAP_INVOKE_ID_TAG))
819     {
820         saved_offset = asn1->offset;
821         item =
822             proto_tree_add_text(tree, asn1->tvb,
823                 saved_offset, -1, "Invoke Id");
824
825         subtree = proto_item_add_subtree(item, ett_component);
826
827         tag = -1;
828         dissect_map_tag(asn1, subtree, &tag, "Invoke Id Tag", &null_item);
829         dissect_map_len(asn1, subtree, &def_len, &len);
830         dissect_map_integer(asn1, subtree, len, "Invoke Id:");
831
832         proto_item_set_len(item, asn1->offset - saved_offset);
833     }
834
835     return(MAP_OK);
836 }
837
838
839 static void
840 dissect_map_problem(ASN1_SCK *asn1, proto_tree *tree)
841 {
842     guint       orig_offset, saved_offset = 0;
843     guint       len, tag_len;
844     guint       tag;
845     proto_tree  *subtree;
846     proto_item  *item = NULL;
847     gchar       *str = NULL;
848     gchar       *type_str = NULL;
849     gint32      spec;
850     gboolean    def_len;
851
852     orig_offset = asn1->offset;
853     saved_offset = asn1->offset;
854     asn1_id_decode1(asn1, &tag);
855     tag_len = asn1->offset - saved_offset;
856
857     item =
858         proto_tree_add_text(tree, asn1->tvb,
859             saved_offset, -1, "Problem Code");
860
861     subtree = proto_item_add_subtree(item, ett_problem);
862
863     dissect_map_len(asn1, subtree, &def_len, &len);
864     proto_item_set_len(item, (asn1->offset - saved_offset) + len);
865
866     if (len != 1)
867     {
868         proto_tree_add_text(subtree, asn1->tvb,
869             asn1->offset, len, "Unknown encoding of Problem Code");
870
871         asn1->offset += len;
872         return;
873     }
874
875     saved_offset = asn1->offset;
876     asn1_int32_value_decode(asn1, 1, &spec);
877
878     switch (tag)
879     {
880     case MAP_GE_PROBLEM_TAG:
881         type_str = "General Problem";
882         switch (spec)
883         {
884         case 0: str = "Unrecognized Component"; break;
885         case 1: str = "Mistyped Component"; break;
886         case 2: str = "Badly Structured Component"; break;
887         default:
888             str = "Undefined";
889             break;
890         }
891         break;
892
893     case MAP_IN_PROBLEM_TAG:
894         type_str = "Invoke";
895         switch (spec)
896         {
897         case 0: str = "Duplicate Invoke ID"; break;
898         case 1: str = "Unrecognized Operation"; break;
899         case 2: str = "Mistyped Parameter"; break;
900         case 3: str = "Resource Limitation"; break;
901         case 4: str = "Initiating Release"; break;
902         case 5: str = "Unrecognized Linked ID"; break;
903         case 6: str = "Linked Response Unexpected"; break;
904         case 7: str = "Unexpected Linked Operation"; break;
905         default:
906             str = "Undefined";
907             break;
908         }
909         break;
910
911     case MAP_RR_PROBLEM_TAG:
912         type_str = "Return Result";
913         switch (spec)
914         {
915         case 0: str = "Unrecognized Invoke ID"; break;
916         case 1: str = "Return Result Unexpected"; break;
917         case 2: str = "Mistyped Parameter"; break;
918         default:
919             str = "Undefined";
920             break;
921         }
922         break;
923
924     case MAP_RE_PROBLEM_TAG:
925         type_str = "Return Error";
926         switch (spec)
927         {
928         case 0: str = "Unrecognized Invoke ID"; break;
929         case 1: str = "Return Error Unexpected"; break;
930         case 2: str = "Unrecognized Error"; break;
931         case 3: str = "Unexpected Error"; break;
932         case 4: str = "Mistyped Parameter"; break;
933         default:
934             str = "Undefined";
935             break;
936         }
937         break;
938
939     default:
940         type_str = "Undefined";
941         break;
942     }
943
944     proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
945         orig_offset, tag_len, tag, type_str);
946
947     proto_tree_add_text(subtree, asn1->tvb,
948         saved_offset, 1, "Problem Specifier %s", str);
949 }
950
951
952 static int
953 dissect_map_lnkId(ASN1_SCK *asn1, proto_tree *tree)
954 {
955     guint       saved_offset = 0;
956     guint       len;
957     guint       tag;
958     proto_item  *item, *null_item;
959     proto_tree  *subtree;
960     gboolean    def_len;
961
962     if (check_map_tag(asn1, MAP_LINK_ID_TAG))
963     {
964         saved_offset = asn1->offset;
965         item =
966             proto_tree_add_text(tree, asn1->tvb,
967                 saved_offset, -1, "Linked Id");
968
969         subtree = proto_item_add_subtree(item, ett_component);
970
971         tag = -1;
972         dissect_map_tag(asn1, tree, &tag, "Linked Id Tag", &null_item);
973         dissect_map_len(asn1, tree, &def_len, &len);
974         dissect_map_integer(asn1, tree, len, "Linked Id:");
975
976         proto_item_set_len(item, asn1->offset - saved_offset);
977     }
978
979     return(MAP_OK);
980 }
981
982
983 static int
984 dissect_map_opr_code(ASN1_SCK *asn1, packet_info *pinfo, proto_tree *tree, gint *op_idx_p)
985 {
986     guint       saved_offset = 0;
987     guint       len;
988     guint       tag;
989     gint32      val;
990     gchar       *str = NULL;
991     proto_item  *item;
992     proto_tree  *subtree;
993     gboolean    def_len;
994
995     if (check_map_tag(asn1, MAP_OPR_CODE_TAG))
996     {
997         tag = -1;
998         dissect_map_tag(asn1, tree, &tag, "Operation Code", &item);
999         subtree = proto_item_add_subtree(item, ett_opr_code);
1000         dissect_map_len(asn1, subtree, &def_len, &len);
1001
1002         saved_offset = asn1->offset;
1003         asn1_int32_value_decode(asn1, len, &val);
1004         proto_tree_add_int(subtree, hf_map_opr_code, asn1->tvb, saved_offset,
1005             asn1->offset - saved_offset, val);
1006
1007         str = my_match_strval(val, opr_code_strings, op_idx_p);
1008
1009         if (NULL == str) return(MAP_FAIL);
1010
1011         if (check_col(pinfo->cinfo, COL_INFO))
1012         {
1013             col_append_fstr(pinfo->cinfo, COL_INFO,  "%s ", str);
1014         }
1015     }
1016
1017     return(MAP_OK);
1018 }
1019
1020
1021 static int
1022 dissect_map_params(ASN1_SCK *asn1, proto_tree *tree)
1023 {
1024     guint       off_tree[100], saved_offset, len_offset;
1025     int         num_seq;
1026     guint       tag, len;
1027     gboolean    def_len = FALSE;
1028     proto_item  *item_tree[100], *item;
1029     proto_tree  *seq_tree[100], *use_tree, *subtree;
1030
1031     num_seq = 0;
1032     use_tree = tree;
1033
1034     while ((tvb_length_remaining(asn1->tvb, asn1->offset) > 0) &&
1035         (!check_map_tag(asn1, 0)))
1036     {
1037         saved_offset = asn1->offset;
1038         asn1_id_decode1(asn1, &tag);
1039         len_offset = asn1->offset;
1040         asn1_length_decode(asn1, &def_len, &len);
1041
1042         if (tag == MAP_SEQ_TAG)
1043         {
1044             item =
1045                 proto_tree_add_text(use_tree, asn1->tvb,
1046                     saved_offset, -1, "Sequence");
1047
1048             subtree = proto_item_add_subtree(item, ett_params);
1049
1050             proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
1051                 saved_offset, len_offset - saved_offset, tag, "Sequence Tag");
1052
1053             if (!def_len)
1054             {
1055                 proto_tree_add_text(subtree, asn1->tvb,
1056                     len_offset, asn1->offset - len_offset, "Length: Indefinite");
1057
1058                 seq_tree[num_seq] = subtree;
1059                 item_tree[num_seq] = item;
1060                 off_tree[num_seq] = saved_offset;
1061                 num_seq++;
1062             }
1063             else
1064             {
1065                 proto_tree_add_uint(subtree, hf_map_length, asn1->tvb,
1066                     len_offset, asn1->offset - len_offset, len);
1067
1068                 proto_item_set_len(item, (asn1->offset - saved_offset) + len);
1069             }
1070
1071             use_tree = subtree;
1072             continue;
1073         }
1074
1075         if (!def_len)
1076         {
1077             proto_tree_add_uint_format(use_tree, hf_map_tag, asn1->tvb,
1078                 saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
1079             proto_tree_add_text(use_tree, asn1->tvb,
1080                 len_offset, asn1->offset - len_offset, "Length: Indefinite");
1081
1082             seq_tree[num_seq] = use_tree;
1083             item_tree[num_seq] = NULL;
1084             num_seq++;
1085             continue;
1086         }
1087         else
1088         {
1089             item =
1090                 proto_tree_add_text(use_tree, asn1->tvb,
1091                     saved_offset, -1, "Parameter");
1092
1093             subtree = proto_item_add_subtree(item, ett_param);
1094
1095             proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
1096                 saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
1097
1098             proto_tree_add_uint(subtree, hf_map_length, asn1->tvb,
1099                 len_offset, asn1->offset - len_offset, len);
1100
1101             proto_item_set_len(item, (asn1->offset - saved_offset) + len);
1102
1103             proto_tree_add_text(subtree, asn1->tvb,
1104                 asn1->offset, len, "Parameter Data");
1105
1106             asn1->offset += len;
1107         }
1108
1109         if (tvb_length_remaining(asn1->tvb, asn1->offset) <=0) break;
1110
1111         while ((num_seq > 0) &&
1112             asn1_eoc(asn1, -1))
1113         {
1114             saved_offset = asn1->offset;
1115             asn1_eoc_decode(asn1, -1);
1116
1117             proto_tree_add_text(seq_tree[num_seq-1], asn1->tvb,
1118                 saved_offset, asn1->offset - saved_offset, "End of Contents");
1119
1120             if (item_tree[num_seq-1] != NULL)
1121             {
1122                 proto_item_set_len(item_tree[num_seq-1], asn1->offset - off_tree[num_seq-1]);
1123             }
1124
1125             num_seq--;
1126         }
1127     }
1128
1129     return(MAP_OK);
1130 }
1131
1132
1133 static int
1134 dissect_map_eoc(ASN1_SCK *asn1, proto_tree *tree)
1135 {
1136     guint       saved_offset;
1137
1138     saved_offset = asn1->offset;
1139
1140     if (tvb_length_remaining(asn1->tvb, saved_offset) <= 0)
1141     {
1142         return(MAP_FAIL);
1143     }
1144
1145     if (!asn1_eoc(asn1, -1))
1146     {
1147         return(MAP_FAIL);
1148     }
1149
1150     asn1_eoc_decode(asn1, -1);
1151
1152     proto_tree_add_text(tree, asn1->tvb,
1153         saved_offset, asn1->offset - saved_offset, "End of Contents");
1154
1155     return(MAP_OK);
1156 }
1157
1158
1159 static void
1160 dissect_map_invoke(ASN1_SCK *asn1, packet_info *pinfo, proto_tree *tree)
1161 {
1162     proto_tree  *subtree;
1163     guint       saved_offset = 0;
1164     guint       len;
1165     guint       tag;
1166     proto_item  *item;
1167     gint        op_idx;
1168     gboolean    def_len;
1169     int         ret;
1170
1171     saved_offset = asn1->offset;
1172     ret = asn1_id_decode1(asn1, &tag);
1173     item = proto_tree_add_text(tree, asn1->tvb, saved_offset, -1, "Components");
1174     subtree = proto_item_add_subtree(item, ett_components);
1175     proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1176                                             tag, "Invoke Type Tag");
1177
1178     dissect_map_len(asn1, subtree, &def_len, &len);
1179
1180     if (def_len)
1181     {
1182         proto_item_set_len(item, (asn1->offset - saved_offset) + len);
1183     }
1184
1185     dissect_map_invokeId(asn1, subtree);
1186
1187     dissect_map_lnkId(asn1, subtree);
1188
1189     if (dissect_map_opr_code(asn1, pinfo, subtree, &op_idx) == MAP_OK)
1190     {
1191         /*
1192          * decode elements
1193          */
1194         if (op_fcn[op_idx] == NULL)
1195         {
1196             dissect_map_params(asn1, subtree);
1197         }
1198         else
1199         {
1200             (*op_fcn[op_idx])(asn1, subtree);
1201         }
1202     }
1203
1204     if (!def_len)
1205     {
1206         dissect_map_eoc(asn1, subtree);
1207     }
1208 }
1209
1210
1211 static void
1212 dissect_map_rr(ASN1_SCK *asn1, packet_info *pinfo, proto_tree *tree, gchar *str)
1213 {
1214     guint       tag, len, comp_len;
1215     gint        op_idx;
1216     guint       saved_offset;
1217     proto_item  *item, *null_item;
1218     proto_tree  *subtree;
1219     gboolean    def_len;
1220     gboolean    comp_def_len;
1221
1222     tag = -1;
1223     saved_offset = asn1->offset;
1224     asn1_id_decode1(asn1, &tag);
1225
1226     item = proto_tree_add_text(tree, asn1->tvb, saved_offset, -1, "Components");
1227
1228     subtree = proto_item_add_subtree(item, ett_components);
1229
1230     proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb,
1231         saved_offset, asn1->offset - saved_offset, tag, str);
1232
1233     dissect_map_len(asn1, subtree, &comp_def_len, &comp_len);
1234
1235     if (comp_def_len)
1236     {
1237         proto_item_set_len(item, (asn1->offset - saved_offset) + comp_len);
1238     }
1239
1240     dissect_map_invokeId(asn1, subtree);
1241
1242     if (check_map_tag(asn1, MAP_SEQ_TAG))
1243     {
1244         tag = -1;
1245         dissect_map_tag(asn1, subtree, &tag, "Sequence Tag", &null_item);
1246         dissect_map_len(asn1, subtree, &def_len, &len);
1247     }
1248
1249     if (dissect_map_opr_code(asn1, pinfo, subtree, &op_idx) == MAP_OK)
1250     {
1251         dissect_map_params(asn1, subtree);
1252     }
1253
1254     if (!comp_def_len)
1255     {
1256         dissect_map_eoc(asn1, subtree);
1257     }
1258 }
1259
1260
1261 static int
1262 dissect_map_re(ASN1_SCK *asn1, proto_tree *tree)
1263 {
1264     guint       tag, len, comp_len;
1265     guint       saved_offset;
1266     proto_item  *item, *null_item;
1267     proto_tree  *subtree;
1268     gboolean    def_len;
1269
1270     tag = -1;
1271     saved_offset = asn1->offset;
1272     asn1_id_decode1(asn1, &tag);
1273
1274     item = proto_tree_add_text(tree, asn1->tvb, saved_offset, -1, "Components");
1275
1276     subtree = proto_item_add_subtree(item, ett_components);
1277
1278     proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1279         tag, "Return Error Type Tag");
1280
1281     dissect_map_len(asn1, subtree, &def_len, &comp_len);
1282
1283     if (def_len)
1284     {
1285         proto_item_set_len(item, (asn1->offset - saved_offset) + comp_len);
1286     }
1287
1288     saved_offset = asn1->offset;
1289     dissect_map_invokeId(asn1, subtree);
1290
1291 #define MAP_LOCAL_ERR_CODE_TAG 0x2
1292 #define MAP_GBL_ERR_CODE_TAG 0x6
1293     if (check_map_tag(asn1, MAP_LOCAL_ERR_CODE_TAG))
1294     {
1295         tag = -1;
1296         dissect_map_tag(asn1, subtree, &tag, "Local Error Code Tag", &null_item);
1297     }
1298     else if (check_map_tag(asn1, MAP_GBL_ERR_CODE_TAG))
1299     {
1300         tag = -1;
1301         dissect_map_tag(asn1, subtree, &tag, "Global Error Code Tag", &null_item);
1302     }
1303     else
1304     {
1305         proto_tree_add_text(subtree, asn1->tvb, asn1->offset, comp_len,
1306             "Unknown Error Code");
1307
1308         asn1->offset += (comp_len - (asn1->offset - saved_offset));
1309         return(MAP_OK);
1310     }
1311
1312     dissect_map_len(asn1, subtree, &def_len, &len);
1313     dissect_map_integer(asn1, subtree, len, "Error Code:");
1314
1315     dissect_map_params(asn1, subtree);
1316
1317     if (!def_len)
1318     {
1319         dissect_map_eoc(asn1, subtree);
1320     }
1321
1322     return(MAP_OK);
1323 }
1324
1325
1326 static void
1327 dissect_map_reject(ASN1_SCK *asn1, proto_tree *tree)
1328 {
1329     guint       tag, len;
1330     guint       saved_offset;
1331     proto_item  *item;
1332     proto_tree  *subtree;
1333     gboolean    def_len;
1334
1335     tag = -1;
1336
1337     saved_offset = asn1->offset;
1338     asn1_id_decode1(asn1, &tag);
1339
1340     item = proto_tree_add_text(tree, asn1->tvb, saved_offset, -1, "Components");
1341
1342     subtree = proto_item_add_subtree(item, ett_components);
1343
1344     proto_tree_add_uint_format(subtree, hf_map_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1345         tag, "Reject Type Tag");
1346
1347     dissect_map_len(asn1, subtree, &def_len, &len);
1348
1349     if (def_len)
1350     {
1351         proto_item_set_len(item, (asn1->offset - saved_offset) + len);
1352     }
1353
1354     dissect_map_invokeId(asn1, subtree);
1355     dissect_map_problem(asn1, subtree);
1356
1357     if (!def_len)
1358     {
1359         dissect_map_eoc(asn1, subtree);
1360     }
1361 }
1362
1363
1364 static void
1365 dissect_map_message(packet_info *pinfo, proto_tree *map_tree, ASN1_SCK *asn1)
1366 {
1367     guint       tag;
1368     guint       saved_offset;
1369     gchar       *str = NULL;
1370     static int  i = 0;
1371
1372     saved_offset = asn1->offset;
1373     asn1_id_decode1(asn1, &tag);
1374     asn1->offset = saved_offset;
1375
1376     str = match_strval(tag, tag_strings);
1377
1378     if (NULL == str) return;
1379
1380     if (check_col(pinfo->cinfo, COL_INFO))
1381     {
1382         if (0 == i)
1383         {
1384             col_append_fstr(pinfo->cinfo, COL_INFO,  "%s ", str);
1385         }
1386         else
1387         {
1388             col_append_fstr(pinfo->cinfo, COL_INFO,  "& %s ", str);
1389         }
1390     }
1391
1392     switch(tag)
1393     {
1394     case MAP_TC_INVOKE :
1395         dissect_map_invoke(asn1, pinfo, map_tree);
1396         break;
1397
1398     case MAP_TC_RRL :
1399         dissect_map_rr(asn1, pinfo, map_tree, "Return Result(Last) Type Tag");
1400         break;
1401
1402     case MAP_TC_RE :
1403         dissect_map_re(asn1, map_tree);
1404         break;
1405
1406     case MAP_TC_REJECT :
1407         dissect_map_reject(asn1, map_tree);
1408         break;
1409
1410     case MAP_TC_RRN :
1411         dissect_map_rr(asn1, pinfo, map_tree, "Return Result(Not Last) Type Tag");
1412         break;
1413
1414     default:
1415         proto_tree_add_text(map_tree, asn1->tvb, saved_offset, -1,
1416             "Message type not handled, ignoring");
1417         break;
1418     }
1419 }
1420
1421
1422 static void
1423 dissect_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1424 {
1425     proto_item  *ti;
1426     proto_tree  *map_tree;
1427     ASN1_SCK    asn1;
1428     int         offset = 0;
1429
1430     /*
1431      * Make entries in Protocol column on summary display
1432      */
1433     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1434     {
1435         col_set_str(pinfo->cinfo, COL_PROTOCOL, "GSM MAP");
1436     }
1437
1438
1439     /* In the interest of speed, if "tree" is NULL, don't do any work not
1440      * necessary to generate protocol tree items.
1441      */
1442     if (tree)
1443     {
1444         /* create display subtree for the protocol */
1445         ti = proto_tree_add_item(tree, proto_map, tvb, 0, -1, FALSE);
1446
1447         map_tree = proto_item_add_subtree(ti, ett_map);
1448
1449         asn1_open(&asn1, tvb, offset);
1450
1451         dissect_map_message(pinfo, map_tree, &asn1);
1452
1453         asn1_close(&asn1, &offset);
1454     }
1455 }
1456
1457
1458 /* Register the protocol with Ethereal */
1459
1460 void
1461 proto_register_map(void)
1462 {
1463     guint               i;
1464     gint                last_offset;
1465
1466     /* Setup list of header fields  See Section 1.6.1 for details*/
1467     static hf_register_info hf[] =
1468     {
1469         { &hf_map_tag,
1470             { "Tag",            "map.msgtype",
1471             FT_UINT8, BASE_HEX, NULL, 0,
1472             "", HFILL }
1473         },
1474         { &hf_map_length,
1475             { "Length",         "map.len",
1476             FT_UINT8, BASE_HEX, NULL, 0,
1477             "", HFILL }
1478         },
1479         { &hf_map_opr_code,
1480             { "Operation Code", "map.oprcode",
1481             FT_INT32, BASE_DEC, VALS(opr_code_strings), 0,
1482             "", HFILL }
1483         },
1484         { &hf_map_int,
1485             { "Integer Data",   "map.data",
1486             FT_INT32, BASE_DEC, 0, 0,
1487             "", HFILL }
1488         },
1489     };
1490
1491     /* Setup protocol subtree array */
1492 #define NUM_INDIVIDUAL_PARAMS   7
1493     static gint *ett[NUM_INDIVIDUAL_PARAMS+GSM_MAP_NUM_OP+NUM_PARAM_1];
1494
1495     memset((void *) ett, 0, sizeof(ett));
1496
1497     ett[0] = &ett_map;
1498     ett[1] = &ett_opr_code;
1499     ett[2] = &ett_component;
1500     ett[3] = &ett_components;
1501     ett[4] = &ett_param;
1502     ett[5] = &ett_params;
1503     ett[6] = &ett_problem;
1504
1505     last_offset = NUM_INDIVIDUAL_PARAMS;
1506
1507     for (i=0; i < GSM_MAP_NUM_OP; i++, last_offset++)
1508     {
1509         ett_op[i] = -1;
1510         ett[last_offset] = &ett_op[i];
1511     }
1512
1513     for (i=0; i < NUM_PARAM_1; i++, last_offset++)
1514     {
1515         ett_param_1[i] = -1;
1516         ett[last_offset] = &ett_param_1[i];
1517     }
1518
1519     /* Register the protocol name and description */
1520     proto_map =
1521         proto_register_protocol("GSM Mobile Application Part",
1522             "GSM MAP", "gsm_map");
1523
1524     /* Required function calls to register the header fields and subtrees used */
1525     proto_register_field_array(proto_map, hf, array_length(hf));
1526     proto_register_subtree_array(ett, array_length(ett));
1527 }
1528
1529 void
1530 proto_reg_handoff_map(void)
1531 {
1532     dissector_handle_t  map_handle;
1533
1534     map_handle = create_dissector_handle(dissect_map, proto_map);
1535     dissector_add("tcap.itu_ssn", 6, map_handle);
1536     dissector_add("tcap.itu_ssn", 7, map_handle);
1537     dissector_add("tcap.itu_ssn", 8, map_handle);
1538     dissector_add("tcap.itu_ssn", 9, map_handle);
1539 }