3 * Gateway Control Protocol -- Context Tracking
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * - handle text-encoded termination wildcards adequtelly
29 * - avoid persistent tracking of NULL and ALL contexts
34 #include <epan/emem.h>
38 static wmem_tree_t
* msgs
= NULL
;
39 static wmem_tree_t
* trxs
= NULL
;
40 static wmem_tree_t
* ctxs_by_trx
= NULL
;
41 static wmem_tree_t
* ctxs
= NULL
;
43 const value_string gcp_cmd_type
[] = {
44 { GCP_CMD_NONE
, "NoCommand"},
45 { GCP_CMD_ADD_REQ
, "addReq"},
46 { GCP_CMD_MOVE_REQ
, "moveReq"},
47 { GCP_CMD_MOD_REQ
, "modReq"},
48 { GCP_CMD_SUB_REQ
, "subtractReq"},
49 { GCP_CMD_AUDITCAP_REQ
, "auditCapRequest"},
50 { GCP_CMD_AUDITVAL_REQ
, "auditValueRequest"},
51 { GCP_CMD_NOTIFY_REQ
, "notifyReq"},
52 { GCP_CMD_SVCCHG_REQ
, "serviceChangeReq"},
53 { GCP_CMD_TOPOLOGY_REQ
, "topologyReq"},
54 { GCP_CMD_CTX_ATTR_AUDIT_REQ
, "ctxAttrAuditReq"},
55 { GCP_CMD_ADD_REPLY
, "addReply"},
56 { GCP_CMD_MOVE_REPLY
, "moveReply"},
57 { GCP_CMD_MOD_REPLY
, "modReply"},
58 { GCP_CMD_SUB_REPLY
, "subtractReply"},
59 { GCP_CMD_AUDITCAP_REPLY
, "auditCapReply"},
60 { GCP_CMD_AUDITVAL_REPLY
, "auditValReply"},
61 { GCP_CMD_NOTIFY_REPLY
, "notifyReply"},
62 { GCP_CMD_SVCCHG_REPLY
, "serviceChangeReply"},
63 { GCP_CMD_TOPOLOGY_REPLY
, "topologyReply"},
67 const value_string gcp_term_types
[] = {
68 { GCP_TERM_TYPE_AAL1
, "aal1" },
69 { GCP_TERM_TYPE_AAL2
, "aal2" },
70 { GCP_TERM_TYPE_AAL1_STRUCT
, "aal1struct" },
71 { GCP_TERM_TYPE_IP_RTP
, "ipRtp" },
72 { GCP_TERM_TYPE_TDM
, "tdm" },
78 static gboolean gcp_initialized
= FALSE
;
83 msgs
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
84 trxs
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
85 ctxs_by_trx
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
86 ctxs
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
87 gcp_initialized
= TRUE
;
90 gcp_msg_t
* gcp_msg(packet_info
* pinfo
, int o
, gboolean keep_persistent_data
) {
92 guint32 framenum
= (guint32
)pinfo
->fd
->num
;
93 guint32 offset
= (guint32
)o
;
94 address
* src
= &(pinfo
->src
);
95 address
* dst
= &(pinfo
->dst
);
99 if (keep_persistent_data
) {
100 wmem_tree_key_t key
[] = {
106 if (( m
= (gcp_msg_t
*)wmem_tree_lookup32_array(msgs
,key
) )) {
110 m
= wmem_new(wmem_file_scope(), gcp_msg_t
);
111 m
->framenum
= framenum
;
112 m
->time
= pinfo
->fd
->abs_ts
;
116 wmem_tree_insert32_array(msgs
,key
,m
);
119 m
= wmem_new0(wmem_packet_scope(), gcp_msg_t
);
120 m
->framenum
= framenum
;
125 if (CMP_ADDRESS(src
, dst
) < 0) {
133 switch(lo_addr
->type
) {
139 memcpy((guint8
*)&(m
->hi_addr
),hi_addr
->data
,4);
140 memcpy((guint8
*)&(m
->lo_addr
),lo_addr
->data
,4);
143 m
->hi_addr
= mtp3_pc_hash((const mtp3_addr_pc_t
*)hi_addr
->data
);
144 m
->lo_addr
= mtp3_pc_hash((const mtp3_addr_pc_t
*)lo_addr
->data
);
147 /* XXX: heuristic and error prone */
148 m
->hi_addr
= g_str_hash(ep_address_to_str(hi_addr
));
149 m
->lo_addr
= g_str_hash(ep_address_to_str(lo_addr
));
156 gcp_trx_t
* gcp_trx(gcp_msg_t
* m
,guint32 t_id
, gcp_trx_type_t type
, gboolean keep_persistent_data
) {
158 gcp_trx_msg_t
* trxmsg
;
160 if ( !m
) return NULL
;
162 if (keep_persistent_data
) {
165 for ( trxmsg
= m
->trxs
; trxmsg
; trxmsg
= trxmsg
->next
) {
166 if (trxmsg
->trx
&& trxmsg
->trx
->id
== t_id
) {
170 DISSECTOR_ASSERT_NOT_REACHED();
172 wmem_tree_key_t key
[] = {
179 trxmsg
= wmem_new(wmem_file_scope(), gcp_trx_msg_t
);
180 t
= (gcp_trx_t
*)wmem_tree_lookup32_array(trxs
,key
);
183 t
= wmem_new(wmem_file_scope(), gcp_trx_t
);
191 wmem_tree_insert32_array(trxs
,key
,t
);
194 /* XXX: request, reply and ack + point to frames where they are */
196 case GCP_TRX_PENDING
:
205 t
= wmem_new(wmem_packet_scope(), gcp_trx_t
);
206 trxmsg
= wmem_new(wmem_packet_scope(), gcp_trx_msg_t
);
215 DISSECTOR_ASSERT(trxmsg
);
219 trxmsg
->last
= trxmsg
;
222 m
->trxs
->last
= m
->trxs
->last
->next
= trxmsg
;
231 gcp_ctx_t
* gcp_ctx(gcp_msg_t
* m
, gcp_trx_t
* t
, guint32 c_id
, gboolean persistent
) {
232 gcp_ctx_t
* context
= NULL
;
233 gcp_ctx_t
** context_p
= NULL
;
235 if ( !m
|| !t
) return NULL
;
239 wmem_tree_key_t ctx_key
[] = {
246 wmem_tree_key_t trx_key
[] = {
254 if (( context
= (gcp_ctx_t
*)wmem_tree_lookup32_array(ctxs_by_trx
,trx_key
) )) {
256 } if ((context_p
= (gcp_ctx_t
**)wmem_tree_lookup32_array(ctxs
,ctx_key
))) {
257 context
= *context_p
;
260 if (context
->initial
->framenum
<= m
->framenum
) {
263 } while(( context
= context
->prev
));
265 DISSECTOR_ASSERT(! "a context should exist");
268 if (c_id
== CHOOSE_CONTEXT
) {
269 if (! ( context
= (gcp_ctx_t
*)wmem_tree_lookup32_array(ctxs_by_trx
,trx_key
))) {
270 context
= wmem_new(wmem_file_scope(), gcp_ctx_t
);
271 context
->initial
= m
;
272 context
->cmds
= NULL
;
274 context
->terms
.last
= &(context
->terms
);
275 context
->terms
.next
= NULL
;
276 context
->terms
.term
= NULL
;
278 wmem_tree_insert32_array(ctxs_by_trx
,trx_key
,context
);
281 if (( context
= (gcp_ctx_t
*)wmem_tree_lookup32_array(ctxs_by_trx
,trx_key
) )) {
282 if (( context_p
= (gcp_ctx_t
**)wmem_tree_lookup32_array(ctxs
,ctx_key
) )) {
283 if (context
!= *context_p
) {
284 if(context
->id
!= CHOOSE_CONTEXT
) {
285 context
= wmem_new(wmem_file_scope(), gcp_ctx_t
);
287 context
->initial
= m
;
289 context
->cmds
= NULL
;
290 context
->terms
.last
= &(context
->terms
);
291 context
->terms
.next
= NULL
;
292 context
->terms
.term
= NULL
;
294 context
->prev
= *context_p
;
295 *context_p
= context
;
298 context_p
= wmem_new(wmem_file_scope(), gcp_ctx_t
*);
299 *context_p
= context
;
300 context
->initial
= m
;
302 wmem_tree_insert32_array(ctxs
,ctx_key
,context_p
);
304 } else if (! ( context_p
= (gcp_ctx_t
**)wmem_tree_lookup32_array(ctxs
,ctx_key
) )) {
305 context
= wmem_new(wmem_file_scope(), gcp_ctx_t
);
306 context
->initial
= m
;
308 context
->cmds
= NULL
;
309 context
->terms
.last
= &(context
->terms
);
310 context
->terms
.next
= NULL
;
311 context
->terms
.term
= NULL
;
313 context_p
= wmem_new(wmem_file_scope(), gcp_ctx_t
*);
314 *context_p
= context
;
315 wmem_tree_insert32_array(ctxs
,ctx_key
,context_p
);
317 context
= *context_p
;
322 context
= wmem_new(wmem_packet_scope(), gcp_ctx_t
);
323 context
->initial
= m
;
324 context
->cmds
= NULL
;
326 context
->terms
.last
= &(context
->terms
);
327 context
->terms
.next
= NULL
;
328 context
->terms
.term
= NULL
;
334 gcp_cmd_t
* gcp_cmd(gcp_msg_t
* m
, gcp_trx_t
* t
, gcp_ctx_t
* c
, gcp_cmd_type_t type
, guint offset
, gboolean persistent
) {
336 gcp_cmd_msg_t
* cmdtrx
;
337 gcp_cmd_msg_t
* cmdctx
;
339 if ( !m
|| !t
|| !c
) return NULL
;
343 DISSECTOR_ASSERT(t
->cmds
!= NULL
);
345 for (cmdctx
= t
->cmds
; cmdctx
; cmdctx
= cmdctx
->next
) {
347 if (cmd
->msg
== m
&& cmd
->offset
== offset
) {
352 DISSECTOR_ASSERT(!"called for a command that does not exist!");
356 cmd
= wmem_new(wmem_file_scope(), gcp_cmd_t
);
357 cmdtrx
= wmem_new(wmem_file_scope(), gcp_cmd_msg_t
);
358 cmdctx
= wmem_new(wmem_file_scope(), gcp_cmd_msg_t
);
361 cmd
= wmem_new(wmem_packet_scope(), gcp_cmd_t
);
362 cmdtrx
= wmem_new(wmem_packet_scope(), gcp_cmd_msg_t
);
363 cmdctx
= wmem_new(wmem_packet_scope(), gcp_cmd_msg_t
);
367 cmd
->offset
= offset
;
368 cmd
->terms
.term
= NULL
;
369 cmd
->terms
.next
= NULL
;
370 cmd
->terms
.last
= &(cmd
->terms
);
377 cmdctx
->cmd
= cmdtrx
->cmd
= cmd
;
378 cmdctx
->next
= cmdtrx
->next
= NULL
;
379 cmdctx
->last
= cmdtrx
->last
= NULL
;
382 t
->cmds
->last
->next
= cmdtrx
;
383 t
->cmds
->last
= cmdtrx
;
386 t
->cmds
->last
= cmdtrx
;
390 c
->cmds
->last
->next
= cmdctx
;
391 c
->cmds
->last
= cmdctx
;
394 c
->cmds
->last
= cmdctx
;
401 gcp_term_t
* gcp_cmd_add_term(gcp_msg_t
* m
, gcp_trx_t
* tr
, gcp_cmd_t
* c
, gcp_term_t
* t
, gcp_wildcard_t wildcard
, gboolean persistent
) {
405 static gcp_term_t all_terms
= {"$",(guint8
*)"",1,GCP_TERM_TYPE_UNKNOWN
,NULL
,NULL
,NULL
};
407 if ( !c
) return NULL
;
409 if ( wildcard
== GCP_WILDCARD_CHOOSE
) {
414 if ( c
->msg
->commited
) {
415 if (wildcard
== GCP_WILDCARD_ALL
) {
416 for (ct
= c
->ctx
->terms
.next
; ct
; ct
= ct
->next
) {
417 /* XXX not handling more wilcards in one msg */
418 if ( ct
->term
->start
== m
) {
424 for (ct
= c
->ctx
->terms
.next
; ct
; ct
= ct
->next
) {
425 if ( g_str_equal(ct
->term
->str
,t
->str
) ) {
433 for (ct
= c
->ctx
->terms
.next
; ct
; ct
= ct
->next
) {
434 if ( g_str_equal(ct
->term
->str
,t
->str
) || ct
->term
->start
== m
) {
441 if (wildcard
== GCP_WILDCARD_ALL
) {
442 ct
= wmem_new(wmem_file_scope(), gcp_terms_t
);
444 ct
->term
= wmem_new0(wmem_file_scope(), gcp_term_t
);
448 ct
->term
->buffer
= NULL
;
451 c
->terms
.last
= c
->terms
.last
->next
= ct
;
453 ct2
= wmem_new0(wmem_file_scope(), gcp_terms_t
);
454 ct2
->term
= ct
->term
;
456 c
->ctx
->terms
.last
->next
= ct2
;
457 c
->ctx
->terms
.last
= ct2
;
461 for (ct
= c
->ctx
->terms
.next
; ct
; ct
= ct
->next
) {
462 /* XXX not handling more wilcards in one msg */
463 if ( ct
->term
->buffer
== NULL
&& tr
->cmds
->cmd
->msg
== ct
->term
->start
) {
464 ct
->term
->str
= wmem_strdup(wmem_file_scope(), t
->str
);
465 ct
->term
->buffer
= (const guint8
*)wmem_memdup(wmem_file_scope(), t
->buffer
,t
->len
);
466 ct
->term
->len
= t
->len
;
468 ct2
= wmem_new0(wmem_file_scope(), gcp_terms_t
);
469 ct2
->term
= ct
->term
;
471 c
->terms
.last
= c
->terms
.last
->next
= ct2
;
476 if ( g_str_equal(ct
->term
->str
,t
->str
) ) {
477 ct2
= wmem_new0(wmem_file_scope(), gcp_terms_t
);
478 ct2
->term
= ct
->term
;
480 c
->terms
.last
= c
->terms
.last
->next
= ct2
;
486 ct
= wmem_new(wmem_file_scope(), gcp_terms_t
);
488 ct
->term
= wmem_new0(wmem_file_scope(), gcp_term_t
);
491 ct
->term
->str
= wmem_strdup(wmem_file_scope(), t
->str
);
492 ct
->term
->buffer
= (const guint8
*)wmem_memdup(wmem_file_scope(), t
->buffer
,t
->len
);
493 ct
->term
->len
= t
->len
;
495 ct2
= wmem_new0(wmem_file_scope(), gcp_terms_t
);
496 ct2
->term
= ct
->term
;
498 c
->terms
.last
= c
->terms
.last
->next
= ct2
;
500 ct2
= wmem_new0(wmem_file_scope(), gcp_terms_t
);
501 ct2
->term
= ct
->term
;
503 c
->ctx
->terms
.last
= c
->ctx
->terms
.last
->next
= ct2
;
508 ct2
= wmem_new0(wmem_file_scope(), gcp_terms_t
);
509 ct2
->term
= ct
->term
;
511 c
->terms
.last
= c
->terms
.last
->next
= ct2
;
515 DISSECTOR_ASSERT_NOT_REACHED();
518 ct
= wmem_new(wmem_packet_scope(), gcp_terms_t
);
521 c
->terms
.last
= c
->terms
.last
->next
= ct
;
528 const gchar
* gcp_cmd_to_str(gcp_cmd_t
* c
, gboolean persistent
) {
532 if ( !c
) return "-";
538 case GCP_CMD_ADD_REQ
:
541 case GCP_CMD_MOVE_REQ
:
544 case GCP_CMD_MOD_REQ
:
547 case GCP_CMD_SUB_REQ
:
550 case GCP_CMD_AUDITCAP_REQ
:
553 case GCP_CMD_AUDITVAL_REQ
:
556 case GCP_CMD_NOTIFY_REQ
:
559 case GCP_CMD_SVCCHG_REQ
:
562 case GCP_CMD_TOPOLOGY_REQ
:
565 case GCP_CMD_CTX_ATTR_AUDIT_REQ
:
566 s
= "CtxAttribAuditReq {";
568 case GCP_CMD_ADD_REPLY
:
571 case GCP_CMD_MOVE_REPLY
:
574 case GCP_CMD_MOD_REPLY
:
577 case GCP_CMD_SUB_REPLY
:
580 case GCP_CMD_AUDITCAP_REPLY
:
581 s
= "AuditCapReply {";
583 case GCP_CMD_AUDITVAL_REPLY
:
584 s
= "AuditValReply {";
586 case GCP_CMD_NOTIFY_REPLY
:
589 case GCP_CMD_SVCCHG_REPLY
:
592 case GCP_CMD_TOPOLOGY_REPLY
:
593 s
= "TopologyReply {";
598 case GCP_CMD_OTHER_REQ
:
606 for (term
= c
->terms
.next
; term
; term
= term
->next
) {
607 s
= wmem_strdup_printf(wmem_packet_scope(), "%s %s",s
,term
->term
->str
);
611 s
= wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s
,c
->error
);
614 s
= wmem_strdup_printf(wmem_packet_scope(), "%s }", s
);
617 if (! c
->str
) c
->str
= wmem_strdup(wmem_file_scope(), s
);
625 static const gchar
* gcp_trx_to_str(gcp_msg_t
* m
, gcp_trx_t
* t
, gboolean persistent
) {
629 if ( !m
|| !t
) return "-";
631 s
= wmem_strdup_printf(wmem_packet_scope(), "T %x { ",t
->id
);
634 if (t
->cmds
->cmd
->ctx
) {
635 s
= wmem_strdup_printf(wmem_packet_scope(), "%s C %x {",s
,t
->cmds
->cmd
->ctx
->id
);
637 for (c
= t
->cmds
; c
; c
= c
->next
) {
638 if (c
->cmd
->msg
== m
) {
639 s
= wmem_strdup_printf(wmem_packet_scope(), "%s %s",s
,gcp_cmd_to_str(c
->cmd
,persistent
));
643 s
= wmem_strdup_printf(wmem_packet_scope(), "%s %s",s
,"}");
648 s
= wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s
,t
->error
);
651 return wmem_strdup_printf(wmem_packet_scope(), "%s %s",s
,"}");
654 const gchar
* gcp_msg_to_str(gcp_msg_t
* m
, gboolean persistent
) {
658 if ( !m
) return "-";
660 for (t
= m
->trxs
; t
; t
= t
->next
) {
661 s
= wmem_strdup_printf(wmem_packet_scope(), "%s %s",s
,gcp_trx_to_str(m
,t
->trx
, persistent
));
667 typedef struct _gcp_ctxs_t
{
668 struct _gcp_ctx_t
* ctx
;
669 struct _gcp_ctxs_t
* next
;
672 /*static const gchar* trx_types[] = {"None","Req","Reply","Pending","Ack"};*/
674 void gcp_analyze_msg(proto_tree
* gcp_tree
, packet_info
* pinfo
, tvbuff_t
* gcp_tvb
, gcp_msg_t
* m
, gcp_hf_ett_t
* ids
, expert_field
* command_err
) {
676 gcp_ctxs_t contexts
= {NULL
,NULL
};
677 gcp_ctxs_t
* ctx_node
;
681 for (t
= m
->trxs
; t
; t
= t
->next
) {
682 for (c
= t
->trx
->cmds
; c
; c
= c
->next
) {
683 gcp_ctx_t
* ctx
= c
->cmd
->ctx
;
685 for (ctx_node
= contexts
.next
; ctx_node
; ctx_node
= ctx_node
->next
) {
686 if (ctx_node
->ctx
->id
== ctx
->id
) {
692 ctx_node
= wmem_new(wmem_packet_scope(), gcp_ctxs_t
);
694 ctx_node
->next
= contexts
.next
;
695 contexts
.next
= ctx_node
;
700 for (ctx_node
= contexts
.next
; ctx_node
; ctx_node
= ctx_node
->next
) {
701 gcp_ctx_t
* ctx
= ctx_node
->ctx
;
702 proto_item
* ctx_item
= proto_tree_add_uint(gcp_tree
,ids
->hf
.ctx
,gcp_tvb
,0,0,ctx
->id
);
703 proto_tree
* ctx_tree
= proto_item_add_subtree(ctx_item
,ids
->ett
.ctx
);
704 gcp_terms_t
*ctx_term
;
706 PROTO_ITEM_SET_GENERATED(ctx_item
);
709 proto_item
* history_item
= proto_tree_add_text(ctx_tree
,gcp_tvb
,0,0,"[ Command History ]");
710 proto_tree
* history_tree
= proto_item_add_subtree(history_item
,ids
->ett
.ctx_cmds
);
712 for (c
= ctx
->cmds
; c
; c
= c
->next
) {
713 proto_item
* cmd_item
= proto_tree_add_uint(history_tree
,ids
->hf
.ctx_cmd
,gcp_tvb
,0,0,c
->cmd
->msg
->framenum
);
714 if (c
->cmd
->str
) proto_item_append_text(cmd_item
," %s ",c
->cmd
->str
);
715 PROTO_ITEM_SET_GENERATED(cmd_item
);
717 expert_add_info(pinfo
, cmd_item
, command_err
);
722 if (( ctx_term
= ctx
->terms
.next
)) {
723 proto_item
* terms_item
= proto_tree_add_text(ctx_tree
,gcp_tvb
,0,0,"[ Terminations Used ]");
724 proto_tree
* terms_tree
= proto_item_add_subtree(terms_item
,ids
->ett
.ctx_terms
);
726 for (; ctx_term
; ctx_term
= ctx_term
->next
) {
727 if ( ctx_term
->term
&& ctx_term
->term
->str
) {
728 proto_item
* pi
= proto_tree_add_string(terms_tree
,ids
->hf
.ctx_term
,gcp_tvb
,0,0,ctx_term
->term
->str
);
729 proto_tree
* term_tree
= proto_item_add_subtree(pi
,ids
->ett
.ctx_term
);
731 PROTO_ITEM_SET_GENERATED(pi
);
733 if (ctx_term
->term
->type
) {
734 pi
= proto_tree_add_uint(term_tree
,ids
->hf
.ctx_term_type
,gcp_tvb
,0,0,ctx_term
->term
->type
);
735 PROTO_ITEM_SET_GENERATED(pi
);
738 if (ctx_term
->term
->bir
) {
739 pi
= proto_tree_add_string(term_tree
,ids
->hf
.ctx_term_bir
,gcp_tvb
,0,0,ctx_term
->term
->bir
);
740 PROTO_ITEM_SET_GENERATED(pi
);
743 if (ctx_term
->term
->nsap
) {
744 pi
= proto_tree_add_string(term_tree
,ids
->hf
.ctx_term_nsap
,gcp_tvb
,0,0,ctx_term
->term
->nsap
);
745 PROTO_ITEM_SET_GENERATED(pi
);
748 if (ctx_term
->term
->bir
&& ctx_term
->term
->nsap
) {
749 gchar
* tmp_key
= wmem_strdup_printf(wmem_packet_scope(), "%s:%s",ctx_term
->term
->nsap
,ctx_term
->term
->bir
);
750 gchar
* key
= g_ascii_strdown(tmp_key
, -1);
751 alcap_tree_from_bearer_key(term_tree
, gcp_tvb
, pinfo
, key
);