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