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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 * - handle text-encoded termination wildcards adequtelly
29 * - avoid persistent tracking of NULL and ALL contexts
38 static emem_tree_t* msgs = NULL;
39 static emem_tree_t* trxs = NULL;
40 static emem_tree_t* ctxs_by_trx = NULL;
41 static emem_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 = se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "gcp_msgs");
84 trxs = se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "gcp_trxs");
85 ctxs_by_trx = se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "gcp_ctxs_by_trx");
86 ctxs = se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "gcp_ctxs");
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 emem_tree_key_t key[] = {
106 if (( m = se_tree_lookup32_array(msgs,key) )) {
110 m = se_alloc(sizeof(gcp_msg_t));
111 m->framenum = framenum;
112 m->time = pinfo->fd->abs_ts;
116 se_tree_insert32_array(msgs,key,m);
119 m = ep_new0(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 emem_tree_key_t key[] = {
179 trxmsg = se_alloc(sizeof(gcp_trx_msg_t));
180 t = se_tree_lookup32_array(trxs,key);
183 t = se_alloc(sizeof(gcp_trx_t));
191 se_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 = ep_new(gcp_trx_t);
206 trxmsg = ep_new(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 emem_tree_key_t ctx_key[] = {
246 emem_tree_key_t trx_key[] = {
254 if (( context = se_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
256 } if ((context_p = se_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 = se_tree_lookup32_array(ctxs_by_trx,trx_key))) {
270 context = se_alloc(sizeof(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 se_tree_insert32_array(ctxs_by_trx,trx_key,context);
281 if (( context = se_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
282 if (( context_p = se_tree_lookup32_array(ctxs,ctx_key) )) {
283 if (context != *context_p) {
284 context = se_alloc(sizeof(gcp_ctx_t));
285 context->initial = m;
287 context->cmds = NULL;
288 context->terms.last = &(context->terms);
289 context->terms.next = NULL;
290 context->terms.term = NULL;
292 context->prev = *context_p;
293 *context_p = context;
296 context_p = se_alloc(sizeof(void*));
297 *context_p = context;
298 context->initial = m;
300 se_tree_insert32_array(ctxs,ctx_key,context_p);
302 } else if (! ( context_p = se_tree_lookup32_array(ctxs,ctx_key) )) {
303 context = se_alloc(sizeof(gcp_ctx_t));
304 context->initial = m;
306 context->cmds = NULL;
307 context->terms.last = &(context->terms);
308 context->terms.next = NULL;
309 context->terms.term = NULL;
311 context_p = se_alloc(sizeof(void*));
312 *context_p = context;
313 se_tree_insert32_array(ctxs,ctx_key,context_p);
315 context = *context_p;
320 context = ep_new(gcp_ctx_t);
321 context->initial = m;
322 context->cmds = NULL;
324 context->terms.last = &(context->terms);
325 context->terms.next = NULL;
326 context->terms.term = NULL;
332 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) {
334 gcp_cmd_msg_t* cmdtrx;
335 gcp_cmd_msg_t* cmdctx;
337 if ( !m || !t || !c ) return NULL;
341 DISSECTOR_ASSERT(t->cmds != NULL);
343 for (cmdctx = t->cmds; cmdctx; cmdctx = cmdctx->next) {
345 if (cmd->msg == m && cmd->offset == offset) {
350 DISSECTOR_ASSERT(!"called for a command that does not exist!");
354 cmd = se_alloc(sizeof(gcp_cmd_t));
355 cmdtrx = se_alloc(sizeof(gcp_cmd_msg_t));
356 cmdctx = se_alloc(sizeof(gcp_cmd_msg_t));
359 cmd = ep_new(gcp_cmd_t);
360 cmdtrx = ep_new(gcp_cmd_msg_t);
361 cmdctx = ep_new(gcp_cmd_msg_t);
365 cmd->offset = offset;
366 cmd->terms.term = NULL;
367 cmd->terms.next = NULL;
368 cmd->terms.last = &(cmd->terms);
375 cmdctx->cmd = cmdtrx->cmd = cmd;
376 cmdctx->next = cmdtrx->next = NULL;
377 cmdctx->last = cmdtrx->last = NULL;
380 t->cmds->last->next = cmdtrx;
381 t->cmds->last = cmdtrx;
384 t->cmds->last = cmdtrx;
388 c->cmds->last->next = cmdctx;
389 c->cmds->last = cmdctx;
392 c->cmds->last = cmdctx;
399 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) {
403 static gcp_term_t all_terms = {"$",(guint8*)"",1,GCP_TERM_TYPE_UNKNOWN,NULL,NULL,NULL};
405 if ( !c ) return NULL;
407 if ( wildcard == GCP_WILDCARD_CHOOSE) {
412 if ( c->msg->commited ) {
413 if (wildcard == GCP_WILDCARD_ALL) {
414 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
415 /* XXX not handling more wilcards in one msg */
416 if ( ct->term->start == m ) {
422 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
423 if ( g_str_equal(ct->term->str,t->str) ) {
431 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
432 if ( g_str_equal(ct->term->str,t->str) || ct->term->start == m) {
439 if (wildcard == GCP_WILDCARD_ALL) {
440 ct = se_alloc(sizeof(gcp_terms_t));
442 ct->term = se_alloc0(sizeof(gcp_term_t));
446 ct->term->buffer = NULL;
449 c->terms.last = c->terms.last->next = ct;
451 ct2 = se_alloc0(sizeof(gcp_terms_t));
452 ct2->term = ct->term;
454 c->ctx->terms.last->next = ct2;
455 c->ctx->terms.last = ct2;
459 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
460 /* XXX not handling more wilcards in one msg */
461 if ( ct->term->buffer == NULL && tr->cmds->cmd->msg == ct->term->start ) {
462 ct->term->str = se_strdup(t->str);
463 ct->term->buffer = se_memdup(t->buffer,t->len);
464 ct->term->len = t->len;
466 ct2 = se_alloc0(sizeof(gcp_terms_t));
467 ct2->term = ct->term;
469 c->terms.last = c->terms.last->next = ct2;
474 if ( g_str_equal(ct->term->str,t->str) ) {
475 ct2 = se_alloc0(sizeof(gcp_terms_t));
476 ct2->term = ct->term;
478 c->terms.last = c->terms.last->next = ct2;
484 ct = se_alloc(sizeof(gcp_terms_t));
486 ct->term = se_alloc0(sizeof(gcp_term_t));
489 ct->term->str = se_strdup(t->str);
490 ct->term->buffer = se_memdup(t->buffer,t->len);
491 ct->term->len = t->len;
493 ct2 = se_alloc0(sizeof(gcp_terms_t));
494 ct2->term = ct->term;
496 c->terms.last = c->terms.last->next = ct2;
498 ct2 = se_alloc0(sizeof(gcp_terms_t));
499 ct2->term = ct->term;
501 c->ctx->terms.last = c->ctx->terms.last->next = ct2;
506 ct2 = se_alloc0(sizeof(gcp_terms_t));
507 ct2->term = ct->term;
509 c->terms.last = c->terms.last->next = ct2;
513 DISSECTOR_ASSERT_NOT_REACHED();
516 ct = ep_new(gcp_terms_t);
519 c->terms.last = c->terms.last->next = ct;
526 gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent) {
530 if ( !c ) return "-";
536 case GCP_CMD_ADD_REQ:
539 case GCP_CMD_MOVE_REQ:
542 case GCP_CMD_MOD_REQ:
545 case GCP_CMD_SUB_REQ:
548 case GCP_CMD_AUDITCAP_REQ:
551 case GCP_CMD_AUDITVAL_REQ:
554 case GCP_CMD_NOTIFY_REQ:
557 case GCP_CMD_SVCCHG_REQ:
560 case GCP_CMD_TOPOLOGY_REQ:
563 case GCP_CMD_CTX_ATTR_AUDIT_REQ:
564 s = "CtxAttribAuditReq {";
566 case GCP_CMD_ADD_REPLY:
569 case GCP_CMD_MOVE_REPLY:
572 case GCP_CMD_MOD_REPLY:
575 case GCP_CMD_SUB_REPLY:
578 case GCP_CMD_AUDITCAP_REPLY:
579 s = "AuditCapReply {";
581 case GCP_CMD_AUDITVAL_REPLY:
582 s = "AuditValReply {";
584 case GCP_CMD_NOTIFY_REPLY:
587 case GCP_CMD_SVCCHG_REPLY:
590 case GCP_CMD_TOPOLOGY_REPLY:
591 s = "TopologyReply {";
596 case GCP_CMD_OTHER_REQ:
604 for (term = c->terms.next; term; term = term->next) {
605 s = ep_strdup_printf("%s %s",s,term->term->str);
609 s = ep_strdup_printf("%s Error=%i",s,c->error);
612 s = ep_strdup_printf("%s }", s);
615 if (! c->str) c->str = se_strdup(s);
623 static gchar* gcp_trx_to_str(gcp_msg_t* m, gcp_trx_t* t, gboolean persistent) {
627 if ( !m || !t ) return "-";
629 s = ep_strdup_printf("T %x { ",t->id);
632 if (t->cmds->cmd->ctx) {
633 s = ep_strdup_printf("%s C %x {",s,t->cmds->cmd->ctx->id);
635 for (c = t->cmds; c; c = c->next) {
636 if (c->cmd->msg == m) {
637 s = ep_strdup_printf("%s %s",s,gcp_cmd_to_str(c->cmd,persistent));
641 s = ep_strdup_printf("%s %s",s,"}");
646 s = ep_strdup_printf("%s Error=%i",s,t->error);
649 return ep_strdup_printf("%s %s",s,"}");
652 gchar* gcp_msg_to_str(gcp_msg_t* m, gboolean persistent) {
656 if ( !m ) return "-";
658 for (t = m->trxs; t; t = t->next) {
659 s = ep_strdup_printf("%s %s",s,gcp_trx_to_str(m,t->trx, persistent));
665 typedef struct _gcp_ctxs_t {
666 struct _gcp_ctx_t* ctx;
667 struct _gcp_ctxs_t* next;
670 /*static const gchar* trx_types[] = {"None","Req","Reply","Pending","Ack"};*/
672 void gcp_analyze_msg(proto_tree* gcp_tree, tvbuff_t* gcp_tvb, gcp_msg_t* m, gcp_hf_ett_t* ids) {
674 gcp_ctxs_t contexts = {NULL,NULL};
675 gcp_ctxs_t* ctx_node;
679 for (t = m->trxs; t; t = t->next) {
680 for (c = t->trx->cmds; c; c = c->next) {
681 gcp_ctx_t* ctx = c->cmd->ctx;
683 for (ctx_node = contexts.next; ctx_node; ctx_node = ctx_node->next) {
684 if (ctx_node->ctx->id == ctx->id) {
690 ctx_node = ep_new(gcp_ctxs_t);
692 ctx_node->next = contexts.next;
693 contexts.next = ctx_node;
698 for (ctx_node = contexts.next; ctx_node; ctx_node = ctx_node->next) {
699 gcp_ctx_t* ctx = ctx_node->ctx;
700 proto_item* ctx_item = proto_tree_add_uint(gcp_tree,ids->hf.ctx,gcp_tvb,0,0,ctx->id);
701 proto_tree* ctx_tree = proto_item_add_subtree(ctx_item,ids->ett.ctx);
702 gcp_terms_t *ctx_term;
704 PROTO_ITEM_SET_GENERATED(ctx_item);
707 proto_item* history_item = proto_tree_add_text(ctx_tree,gcp_tvb,0,0,"[ Command History ]");
708 proto_tree* history_tree = proto_item_add_subtree(history_item,ids->ett.ctx_cmds);
710 for (c = ctx->cmds; c; c = c->next) {
711 proto_item* cmd_item = proto_tree_add_uint(history_tree,ids->hf.ctx_cmd,gcp_tvb,0,0,c->cmd->msg->framenum);
712 if (c->cmd->str) proto_item_append_text(cmd_item," %s ",c->cmd->str);
713 PROTO_ITEM_SET_GENERATED(cmd_item);
715 proto_item_set_expert_flags(cmd_item, PI_RESPONSE_CODE, PI_WARN);
720 if (( ctx_term = ctx->terms.next )) {
721 proto_item* terms_item = proto_tree_add_text(ctx_tree,gcp_tvb,0,0,"[ Terminations Used ]");
722 proto_tree* terms_tree = proto_item_add_subtree(terms_item,ids->ett.ctx_terms);
724 for (; ctx_term; ctx_term = ctx_term->next ) {
725 if ( ctx_term->term && ctx_term->term->str) {
726 proto_item* pi = proto_tree_add_string(terms_tree,ids->hf.ctx_term,gcp_tvb,0,0,ctx_term->term->str);
727 proto_tree* term_tree = proto_item_add_subtree(pi,ids->ett.ctx_term);
729 PROTO_ITEM_SET_GENERATED(pi);
731 if (ctx_term->term->type) {
732 pi = proto_tree_add_uint(term_tree,ids->hf.ctx_term_type,gcp_tvb,0,0,ctx_term->term->type);
733 PROTO_ITEM_SET_GENERATED(pi);
736 if (ctx_term->term->bir) {
737 pi = proto_tree_add_string(term_tree,ids->hf.ctx_term_bir,gcp_tvb,0,0,ctx_term->term->bir);
738 PROTO_ITEM_SET_GENERATED(pi);
741 if (ctx_term->term->nsap) {
742 pi = proto_tree_add_string(term_tree,ids->hf.ctx_term_nsap,gcp_tvb,0,0,ctx_term->term->nsap);
743 PROTO_ITEM_SET_GENERATED(pi);
746 if (ctx_term->term->bir && ctx_term->term->nsap) {
747 gchar* key = ep_strdup_printf("%s:%s",ctx_term->term->nsap,ctx_term->term->bir);
749 alcap_tree_from_bearer_key(term_tree, gcp_tvb, key);