9a8dd442b440eacbcd989684ec3edaca9139e130
[gd/wireshark/.git] / epan / dissectors / asn1 / ansi_tcap / packet-ansi_tcap-template.c
1 /* packet-ansi_tcap-template.c
2  * Routines for ANSI TCAP
3  * Copyright 2007 Anders Broman <anders.broman@ericsson.com>
4  * Built from the gsm-map dissector Copyright 2004 - 2005, Anders Broman <anders.broman@ericsson.com>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  * References: T1.114
12  */
13
14 #include "config.h"
15
16 #include <epan/packet.h>
17 #include <epan/prefs.h>
18 #include <epan/expert.h>
19 #include <epan/oids.h>
20 #include <epan/asn1.h>
21 #include <epan/strutil.h>
22
23 #include "packet-ber.h"
24 #include "packet-tcap.h"
25 #include "packet-ansi_tcap.h"
26
27 #define PNAME  "ANSI Transaction Capabilities Application Part"
28 #define PSNAME "ANSI_TCAP"
29 #define PFNAME "ansi_tcap"
30
31 void proto_register_ansi_tcap(void);
32 void proto_reg_handoff_ansi_tcap(void);
33
34 /* Preference settings */
35 #define ANSI_TCAP_TID_ONLY            0
36 #define ANSI_TCAP_TID_AND_SOURCE      1
37 #define ANSI_TCAP_TID_SOURCE_AND_DEST 2
38 static gint ansi_tcap_response_matching_type = ANSI_TCAP_TID_ONLY;
39
40 /* Initialize the protocol and registered fields */
41 static int proto_ansi_tcap = -1;
42
43 static int hf_ansi_tcapsrt_SessionId = -1;
44 static int hf_ansi_tcapsrt_Duplicate = -1;
45 static int hf_ansi_tcapsrt_BeginSession = -1;
46 static int hf_ansi_tcapsrt_EndSession = -1;
47 static int hf_ansi_tcapsrt_SessionTime = -1;
48 static int hf_ansi_tcap_bit_h = -1;
49 static int hf_ansi_tcap_op_family = -1;
50 static int hf_ansi_tcap_op_specifier = -1;
51
52 #include "packet-ansi_tcap-hf.c"
53
54 /* Initialize the subtree pointers */
55 static gint ett_tcap = -1;
56 static gint ett_param = -1;
57 static gint ett_ansi_tcap_op_code_nat = -1;
58
59 static gint ett_otid = -1;
60 static gint ett_dtid = -1;
61 static gint ett_ansi_tcap_stat = -1;
62
63 static expert_field ei_ansi_tcap_dissector_not_implemented = EI_INIT;
64
65 static struct tcapsrt_info_t * gp_tcapsrt_info;
66 static gboolean tcap_subdissector_used=FALSE;
67
68 static struct tcaphash_context_t * gp_tcap_context=NULL;
69
70 /* Note the high bit should be masked off when registering in this table (0x7fff)*/
71 static dissector_table_t  ansi_tcap_national_opcode_table; /* National Operation Codes */
72
73 #include "packet-ansi_tcap-ett.c"
74
75 #define MAX_SSN 254
76
77 extern gboolean gtcap_PersistentSRT;
78 extern guint gtcap_RepetitionTimeout;
79 extern guint gtcap_LostTimeout;
80
81 /* When several Tcap components are received in a single TCAP message,
82    we have to use several buffers for the stored parameters
83    because else this data are erased during TAP dissector call */
84 #define MAX_TCAP_INSTANCE 10
85 int tcapsrt_global_current=0;
86 struct tcapsrt_info_t tcapsrt_global_info[MAX_TCAP_INSTANCE];
87
88 static dissector_table_t ber_oid_dissector_table=NULL;
89 static const char * cur_oid;
90 static const char * tcapext_oid;
91
92 static dissector_handle_t ansi_map_handle;
93 static dissector_handle_t ain_handle;
94
95 struct ansi_tcap_private_t ansi_tcap_private;
96 #define MAX_TID_STR_LEN 1024
97
98 static void ansi_tcap_ctx_init(struct ansi_tcap_private_t *a_tcap_ctx) {
99   memset(a_tcap_ctx, '\0', sizeof(*a_tcap_ctx));
100   a_tcap_ctx->signature = ANSI_TCAP_CTX_SIGNATURE;
101   a_tcap_ctx->oid_is_present = FALSE;
102   a_tcap_ctx->TransactionID_str = NULL;
103 }
104
105 static const value_string ansi_tcap_national_op_code_family_vals[] = {
106   {  0x0, "All Families" },
107   {  0x1, "Parameter" },
108   {  0x2, "Charging" },
109   {  0x3, "Provide Instructions" },
110   {  0x4, "Connection Control" },
111   {  0x5, "Caller Interaction" },
112   {  0x6, "Send Notification" },
113   {  0x7, "Network Management" },
114   {  0x8, "Procedural" },
115   {  0x9, "Operation Control" },
116   {  0xa, "Report Event" },
117   /* Spare */
118   {  0x7e, "Miscellaneous" },
119   {  0x7f, "Reserved" },
120   { 0, NULL }
121 };
122
123 /* Transaction tracking */
124 /* Transaction table */
125 struct ansi_tcap_invokedata_t {
126     gint OperationCode;
127       /*
128          0 : national,
129          1 : private
130       */
131     gint32 OperationCode_private;
132     gint32 OperationCode_national;
133 };
134
135 static wmem_map_t *TransactionId_table=NULL;
136
137 /* Store Invoke information needed for the corresponding reply */
138 static void
139 save_invoke_data(packet_info *pinfo, proto_tree *tree _U_, tvbuff_t *tvb _U_){
140   struct ansi_tcap_invokedata_t *ansi_tcap_saved_invokedata;
141   gchar *src, *dst;
142   char *buf;
143
144   src = address_to_str(wmem_packet_scope(), &(pinfo->src));
145   dst = address_to_str(wmem_packet_scope(), &(pinfo->dst));
146
147   if ((!pinfo->fd->flags.visited)&&(ansi_tcap_private.TransactionID_str)){
148
149           /* Only do this once XXX I hope it's the right thing to do */
150           /* The hash string needs to contain src and dest to distiguish differnt flows */
151           switch(ansi_tcap_response_matching_type){
152                         case ANSI_TCAP_TID_ONLY:
153                                 buf = wmem_strdup(wmem_packet_scope(), ansi_tcap_private.TransactionID_str);
154                                 break;
155                         case ANSI_TCAP_TID_AND_SOURCE:
156                                 buf = wmem_strdup_printf(wmem_packet_scope(), "%s%s",ansi_tcap_private.TransactionID_str,src);
157                                 break;
158                         case ANSI_TCAP_TID_SOURCE_AND_DEST:
159                         default:
160                                 buf = wmem_strdup_printf(wmem_packet_scope(), "%s%s%s",ansi_tcap_private.TransactionID_str,src,dst);
161                                 break;
162                 }
163
164           /* If the entry allready exists don't owervrite it */
165           ansi_tcap_saved_invokedata = (struct ansi_tcap_invokedata_t *)wmem_map_lookup(TransactionId_table,buf);
166           if(ansi_tcap_saved_invokedata)
167                   return;
168
169           ansi_tcap_saved_invokedata = wmem_new(wmem_file_scope(), struct ansi_tcap_invokedata_t);
170           ansi_tcap_saved_invokedata->OperationCode = ansi_tcap_private.d.OperationCode;
171           ansi_tcap_saved_invokedata->OperationCode_national = ansi_tcap_private.d.OperationCode_national;
172           ansi_tcap_saved_invokedata->OperationCode_private = ansi_tcap_private.d.OperationCode_private;
173
174           wmem_map_insert(TransactionId_table,
175                         wmem_strdup(wmem_file_scope(), buf),
176                         ansi_tcap_saved_invokedata);
177           /*
178           g_warning("Tcap Invoke Hash string %s",buf);
179           */
180   }
181 }
182
183 static gboolean
184 find_saved_invokedata(packet_info *pinfo, proto_tree *tree _U_, tvbuff_t *tvb _U_){
185   struct ansi_tcap_invokedata_t *ansi_tcap_saved_invokedata;
186   gchar *src, *dst;
187   char *buf;
188
189   if (!ansi_tcap_private.TransactionID_str) {
190     return FALSE;
191   }
192
193   src = address_to_str(wmem_packet_scope(), &(pinfo->src));
194   dst = address_to_str(wmem_packet_scope(), &(pinfo->dst));
195
196   /* The hash string needs to contain src and dest to distiguish differnt flows */
197   buf = (char *)wmem_alloc(wmem_packet_scope(), MAX_TID_STR_LEN);
198   buf[0] = '\0';
199   /* Reverse order to invoke */
200   switch(ansi_tcap_response_matching_type){
201         case ANSI_TCAP_TID_ONLY:
202                 g_snprintf(buf,MAX_TID_STR_LEN,"%s",ansi_tcap_private.TransactionID_str);
203                 break;
204         case ANSI_TCAP_TID_AND_SOURCE:
205                 g_snprintf(buf,MAX_TID_STR_LEN,"%s%s",ansi_tcap_private.TransactionID_str,dst);
206                 break;
207         case ANSI_TCAP_TID_SOURCE_AND_DEST:
208         default:
209                 g_snprintf(buf,MAX_TID_STR_LEN,"%s%s%s",ansi_tcap_private.TransactionID_str,dst,src);
210                 break;
211   }
212
213   ansi_tcap_saved_invokedata = (struct ansi_tcap_invokedata_t *)wmem_map_lookup(TransactionId_table, buf);
214   if(ansi_tcap_saved_invokedata){
215           ansi_tcap_private.d.OperationCode                      = ansi_tcap_saved_invokedata->OperationCode;
216           ansi_tcap_private.d.OperationCode_national = ansi_tcap_saved_invokedata->OperationCode_national;
217           ansi_tcap_private.d.OperationCode_private  = ansi_tcap_saved_invokedata->OperationCode_private;
218           return TRUE;
219   }
220   return FALSE;
221 }
222
223 /* As currently ANSI MAP is the only possible sub dissector this function
224  *  must be improved to handle general cases.
225  *
226  *
227  *
228  * TODO:
229  * 1)Handle national codes
230  *     Design option
231  *     - Create a ansi.tcap.national dissector table and have dissectors for
232  *       national codes register there and let ansi tcap call them.
233  * 2)Handle Private codes properly
234  *     Design question
235  *     Unclear how to differentiate between different private "code sets".
236  *     Use SCCP SSN table as before? or a ansi.tcap.private dissector table?
237  *
238  */
239 static gboolean
240 find_tcap_subdissector(tvbuff_t *tvb, asn1_ctx_t *actx, proto_tree *tree){
241         proto_item *item;
242
243         /* If "DialoguePortion objectApplicationId ObjectIDApplicationContext
244          * points to the subdissector this code can be used.
245          *
246         if(ansi_tcap_private.d.oid_is_present){
247                 call_ber_oid_callback(ansi_tcap_private.objectApplicationId_oid, tvb, 0, actx-pinfo, tree, NULL);
248                 return TRUE;
249         }
250         */
251         if(ansi_tcap_private.d.pdu == 1){
252                 /* Save Invoke data for this transaction */
253                 save_invoke_data(actx->pinfo, tree, tvb);
254         }else{
255                 /* Get saved data for this transaction */
256                 if(find_saved_invokedata(actx->pinfo, tree, tvb)){
257                         if(ansi_tcap_private.d.OperationCode == 0){
258                                 /* national */
259                                 item = proto_tree_add_int(tree, hf_ansi_tcap_national, tvb, 0, 0, ansi_tcap_private.d.OperationCode_national);
260                         }else{
261                                 item = proto_tree_add_int(tree, hf_ansi_tcap_private, tvb, 0, 0, ansi_tcap_private.d.OperationCode_private);
262                         }
263                         PROTO_ITEM_SET_GENERATED(item);
264                         ansi_tcap_private.d.OperationCode_item = item;
265                 }
266         }
267         if(ansi_tcap_private.d.OperationCode == 0){
268                 /* national */
269                 guint8 family = (ansi_tcap_private.d.OperationCode_national & 0x7f00)>>8;
270                 guint8 specifier = (guint8)(ansi_tcap_private.d.OperationCode_national & 0xff);
271                 if(!dissector_try_uint(ansi_tcap_national_opcode_table, ansi_tcap_private.d.OperationCode_national, tvb, actx->pinfo, actx->subtree.top_tree)){
272                         proto_tree_add_expert_format(tree, actx->pinfo, &ei_ansi_tcap_dissector_not_implemented, tvb, 0, -1,
273                                         "Dissector for ANSI TCAP NATIONAL code:0x%x(Family %u, Specifier %u) \n"
274                                         "not implemented. Contact Wireshark developers if you want this supported(Spec required)",
275                                         ansi_tcap_private.d.OperationCode_national, family, specifier);
276                         return FALSE;
277                 }
278                 return TRUE;
279         }else if(ansi_tcap_private.d.OperationCode == 1){
280                 /* private */
281                 if((ansi_tcap_private.d.OperationCode_private & 0xff00) == 0x0900){
282                     /* This is abit of a hack as it assumes the private codes with a "family" of 0x09 is ANSI MAP
283                     * See TODO above.
284                     * N.S0005-0 v 1.0 TCAP Formats and Procedures 5-16 Application Services
285                     * 6.3.2 Component Portion
286                     * The Operation Code is partitioned into an Operation Family followed by a
287                     * Specifier associated with each Operation Family member. For TIA/EIA-41 the
288                     * Operation Family is coded as decimal 9. Bit H of the Operation Family is always
289                     * coded as 0.
290                     */
291                     call_dissector_with_data(ansi_map_handle, tvb, actx->pinfo, actx->subtree.top_tree, &ansi_tcap_private);
292
293                     return TRUE;
294                 } else if ((ansi_tcap_private.d.OperationCode_private & 0xf000) == 0x6000) {
295                     call_dissector_with_data(ain_handle, tvb, actx->pinfo, actx->subtree.top_tree, &ansi_tcap_private);
296                     return TRUE;
297                 }
298         }
299         proto_tree_add_expert_format(tree, actx->pinfo, &ei_ansi_tcap_dissector_not_implemented, tvb, 0, -1,
300             "Dissector for ANSI TCAP PRIVATE code:%u not implemented.\n"
301             "Contact Wireshark developers if you want this supported(Spec required)",
302             ansi_tcap_private.d.OperationCode_private);
303         return FALSE;
304 }
305
306 #include "packet-ansi_tcap-fn.c"
307
308
309
310
311 static int
312 dissect_ansi_tcap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
313 {
314     proto_item          *item=NULL;
315     proto_tree          *tree=NULL;
316 #if 0
317     proto_item          *stat_item=NULL;
318     proto_tree          *stat_tree=NULL;
319         gint                    offset = 0;
320     struct tcaphash_context_t * p_tcap_context;
321     dissector_handle_t subdissector_handle;
322 #endif
323         asn1_ctx_t asn1_ctx;
324
325         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
326         ansi_tcap_ctx_init(&ansi_tcap_private);
327
328     asn1_ctx.subtree.top_tree = parent_tree;
329     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ANSI TCAP");
330
331     /* create display subtree for the protocol */
332     if(parent_tree){
333       item = proto_tree_add_item(parent_tree, proto_ansi_tcap, tvb, 0, -1, ENC_NA);
334       tree = proto_item_add_subtree(item, ett_tcap);
335     }
336     cur_oid = NULL;
337     tcapext_oid = NULL;
338
339     gp_tcapsrt_info=tcapsrt_razinfo();
340     tcap_subdissector_used=FALSE;
341     gp_tcap_context=NULL;
342     dissect_ansi_tcap_PackageType(FALSE, tvb, 0, &asn1_ctx, tree, -1);
343
344 #if 0 /* Skip this part for now it will be rewritten */
345     if (g_ansi_tcap_HandleSRT && !tcap_subdissector_used ) {
346                 if (gtcap_DisplaySRT && tree) {
347                         stat_tree = proto_tree_add_subtree(tree, tvb, 0, 0, ett_ansi_tcap_stat, &stat_item, "Stat");
348                         PROTO_ITEM_SET_GENERATED(stat_item);
349                 }
350                 p_tcap_context=tcapsrt_call_matching(tvb, pinfo, stat_tree, gp_tcapsrt_info);
351                 ansi_tcap_private.context=p_tcap_context;
352
353                 /* If the current message is TCAP only,
354                  * save the Application contexte name for the next messages
355                  */
356                 if ( p_tcap_context && cur_oid && !p_tcap_context->oid_present ) {
357                         /* Save the application context and the sub dissector */
358                         g_strlcpy(p_tcap_context->oid, cur_oid, sizeof(p_tcap_context->oid));
359                         if ( (subdissector_handle = dissector_get_string_handle(ber_oid_dissector_table, cur_oid)) ) {
360                                 p_tcap_context->subdissector_handle=subdissector_handle;
361                                 p_tcap_context->oid_present=TRUE;
362                         }
363                 }
364                 if (g_ansi_tcap_HandleSRT && p_tcap_context && p_tcap_context->callback) {
365                         /* Callback fonction for the upper layer */
366                         (p_tcap_context->callback)(tvb, pinfo, stat_tree, p_tcap_context);
367                 }
368         }
369 #endif
370     return tvb_captured_length(tvb);
371 }
372
373
374 void
375 proto_reg_handoff_ansi_tcap(void)
376 {
377     ansi_map_handle = find_dissector_add_dependency("ansi_map", proto_ansi_tcap);
378     ain_handle = find_dissector_add_dependency("ain", proto_ansi_tcap);
379     ber_oid_dissector_table = find_dissector_table("ber.oid");
380 }
381
382
383
384 void
385 proto_register_ansi_tcap(void)
386 {
387     module_t    *ansi_tcap_module;
388
389
390 /* Setup list of header fields  See Section 1.6.1 for details*/
391     static hf_register_info hf[] = {
392         /* Tcap Service Response Time */
393         { &hf_ansi_tcapsrt_SessionId,
394           { "Session Id",
395             "ansi_tcap.srt.session_id",
396             FT_UINT32, BASE_DEC, NULL, 0x0,
397             NULL, HFILL }
398         },
399         { &hf_ansi_tcapsrt_BeginSession,
400           { "Begin Session",
401             "ansi_tcap.srt.begin",
402             FT_FRAMENUM, BASE_NONE, NULL, 0x0,
403             "SRT Begin of Session", HFILL }
404         },
405         { &hf_ansi_tcapsrt_EndSession,
406           { "End Session",
407             "ansi_tcap.srt.end",
408             FT_FRAMENUM, BASE_NONE, NULL, 0x0,
409             "SRT End of Session", HFILL }
410         },
411         { &hf_ansi_tcapsrt_SessionTime,
412           { "Session duration",
413             "ansi_tcap.srt.sessiontime",
414             FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
415             "Duration of the TCAP session", HFILL }
416         },
417         { &hf_ansi_tcapsrt_Duplicate,
418           { "Request Duplicate",
419             "ansi_tcap.srt.duplicate",
420             FT_UINT32, BASE_DEC, NULL, 0x0,
421             NULL, HFILL }
422         },
423         { &hf_ansi_tcap_bit_h,
424           { "Require Reply", "ansi_tcap.req_rep",
425             FT_BOOLEAN, 16, NULL, 0x8000,
426             NULL, HFILL }
427         },
428         { &hf_ansi_tcap_op_family,
429           { "Family",
430             "ansi_tcap.op_family",
431             FT_UINT16, BASE_DEC, VALS(ansi_tcap_national_op_code_family_vals), 0x7f00,
432             NULL, HFILL }
433         },
434         { &hf_ansi_tcap_op_specifier,
435           { "Specifier",
436             "ansi_tcap.op_specifier",
437             FT_UINT16, BASE_DEC, NULL, 0x00ff,
438             NULL, HFILL }
439         },
440 #include "packet-ansi_tcap-hfarr.c"
441     };
442
443 /* Setup protocol subtree array */
444     static gint *ett[] = {
445         &ett_tcap,
446         &ett_param,
447         &ett_otid,
448         &ett_dtid,
449         &ett_ansi_tcap_stat,
450         &ett_ansi_tcap_op_code_nat,
451         #include "packet-ansi_tcap-ettarr.c"
452     };
453
454     static ei_register_info ei[] = {
455         { &ei_ansi_tcap_dissector_not_implemented, { "ansi_tcap.dissector_not_implemented", PI_UNDECODED, PI_WARN, "Dissector not implemented", EXPFILL }},
456     };
457
458     expert_module_t* expert_ansi_tcap;
459
460     static const enum_val_t ansi_tcap_response_matching_type_values[] = {
461         {"Only Transaction ID will be used in Invoke/response matching",                        "Transaction ID only", ANSI_TCAP_TID_ONLY},
462         {"Transaction ID and Source will be used in Invoke/response matching",                  "Transaction ID and Source", ANSI_TCAP_TID_AND_SOURCE},
463         {"Transaction ID Source and Destination will be used in Invoke/response matching",      "Transaction ID Source and Destination", ANSI_TCAP_TID_SOURCE_AND_DEST},
464         {NULL, NULL, -1}
465     };
466
467 /* Register the protocol name and description */
468     proto_ansi_tcap = proto_register_protocol(PNAME, PSNAME, PFNAME);
469     register_dissector("ansi_tcap", dissect_ansi_tcap, proto_ansi_tcap);
470
471    /* Note the high bit should be masked off when registering in this table (0x7fff)*/
472    ansi_tcap_national_opcode_table = register_dissector_table("ansi_tcap.nat.opcode", "ANSI TCAP National Opcodes", proto_ansi_tcap, FT_UINT16, BASE_DEC);
473 /* Required function calls to register the header fields and subtrees used */
474     proto_register_field_array(proto_ansi_tcap, hf, array_length(hf));
475     proto_register_subtree_array(ett, array_length(ett));
476     expert_ansi_tcap = expert_register_protocol(proto_ansi_tcap);
477     expert_register_field_array(expert_ansi_tcap, ei, array_length(ei));
478
479     ansi_tcap_module = prefs_register_protocol(proto_ansi_tcap, proto_reg_handoff_ansi_tcap);
480
481     prefs_register_enum_preference(ansi_tcap_module, "transaction.matchtype",
482                                    "Type of matching invoke/response",
483                                    "Type of matching invoke/response, risk of mismatch if loose matching chosen",
484                                    &ansi_tcap_response_matching_type, ansi_tcap_response_matching_type_values, FALSE);
485
486     TransactionId_table = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), wmem_str_hash, g_str_equal);
487 }