3 * Gateway Control Protocol -- Context Tracking
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * - handle text-encoded termination wildcards adequtelly
27 * - avoid persistent tracking of NULL and ALL contexts
32 #include <epan/emem.h>
36 static wmem_tree_t* msgs = NULL;
37 static wmem_tree_t* trxs = NULL;
38 static wmem_tree_t* ctxs_by_trx = NULL;
39 static wmem_tree_t* ctxs = NULL;
41 const value_string gcp_cmd_type[] = {
42 { GCP_CMD_NONE, "NoCommand"},
43 { GCP_CMD_ADD_REQ, "addReq"},
44 { GCP_CMD_MOVE_REQ, "moveReq"},
45 { GCP_CMD_MOD_REQ, "modReq"},
46 { GCP_CMD_SUB_REQ, "subtractReq"},
47 { GCP_CMD_AUDITCAP_REQ, "auditCapRequest"},
48 { GCP_CMD_AUDITVAL_REQ, "auditValueRequest"},
49 { GCP_CMD_NOTIFY_REQ, "notifyReq"},
50 { GCP_CMD_SVCCHG_REQ, "serviceChangeReq"},
51 { GCP_CMD_TOPOLOGY_REQ, "topologyReq"},
52 { GCP_CMD_CTX_ATTR_AUDIT_REQ, "ctxAttrAuditReq"},
53 { GCP_CMD_ADD_REPLY, "addReply"},
54 { GCP_CMD_MOVE_REPLY, "moveReply"},
55 { GCP_CMD_MOD_REPLY, "modReply"},
56 { GCP_CMD_SUB_REPLY, "subtractReply"},
57 { GCP_CMD_AUDITCAP_REPLY, "auditCapReply"},
58 { GCP_CMD_AUDITVAL_REPLY, "auditValReply"},
59 { GCP_CMD_NOTIFY_REPLY, "notifyReply"},
60 { GCP_CMD_SVCCHG_REPLY, "serviceChangeReply"},
61 { GCP_CMD_TOPOLOGY_REPLY, "topologyReply"},
65 const value_string gcp_term_types[] = {
66 { GCP_TERM_TYPE_AAL1, "aal1" },
67 { GCP_TERM_TYPE_AAL2, "aal2" },
68 { GCP_TERM_TYPE_AAL1_STRUCT, "aal1struct" },
69 { GCP_TERM_TYPE_IP_RTP, "ipRtp" },
70 { GCP_TERM_TYPE_TDM, "tdm" },
76 static gboolean gcp_initialized = FALSE;
81 msgs = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
82 trxs = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
83 ctxs_by_trx = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
84 ctxs = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
85 gcp_initialized = TRUE;
88 gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean keep_persistent_data) {
90 guint32 framenum = (guint32)pinfo->fd->num;
91 guint32 offset = (guint32)o;
92 address* src = &(pinfo->src);
93 address* dst = &(pinfo->dst);
97 if (keep_persistent_data) {
98 wmem_tree_key_t key[3];
101 key[0].key = &(framenum);
103 key[1].key = &offset;
107 if (( m = (gcp_msg_t *)wmem_tree_lookup32_array(msgs,key) )) {
111 m = wmem_new(wmem_file_scope(), gcp_msg_t);
112 m->framenum = framenum;
113 m->time = pinfo->fd->abs_ts;
115 m->committed = FALSE;
117 wmem_tree_insert32_array(msgs,key,m);
120 m = wmem_new0(wmem_packet_scope(), gcp_msg_t);
121 m->framenum = framenum;
123 m->committed = FALSE;
126 if (CMP_ADDRESS(src, dst) < 0) {
134 switch(lo_addr->type) {
140 memcpy((guint8*)&(m->hi_addr),hi_addr->data,4);
141 memcpy((guint8*)&(m->lo_addr),lo_addr->data,4);
144 m->hi_addr = mtp3_pc_hash((const mtp3_addr_pc_t *)hi_addr->data);
145 m->lo_addr = mtp3_pc_hash((const mtp3_addr_pc_t *)lo_addr->data);
148 /* XXX: heuristic and error prone */
149 m->hi_addr = g_str_hash(ep_address_to_str(hi_addr));
150 m->lo_addr = g_str_hash(ep_address_to_str(lo_addr));
157 gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean keep_persistent_data) {
159 gcp_trx_msg_t* trxmsg;
161 if ( !m ) return NULL;
163 if (keep_persistent_data) {
166 for ( trxmsg = m->trxs; trxmsg; trxmsg = trxmsg->next) {
167 if (trxmsg->trx && trxmsg->trx->id == t_id) {
171 DISSECTOR_ASSERT_NOT_REACHED();
173 wmem_tree_key_t key[4];
176 key[0].key = &(m->hi_addr);
178 key[1].key = &(m->lo_addr);
180 key[2].key = &(t_id);
184 trxmsg = wmem_new(wmem_file_scope(), gcp_trx_msg_t);
185 t = (gcp_trx_t *)wmem_tree_lookup32_array(trxs,key);
188 t = wmem_new(wmem_file_scope(), gcp_trx_t);
196 wmem_tree_insert32_array(trxs,key,t);
199 /* XXX: request, reply and ack + point to frames where they are */
201 case GCP_TRX_PENDING:
210 t = wmem_new(wmem_packet_scope(), gcp_trx_t);
211 trxmsg = wmem_new(wmem_packet_scope(), gcp_trx_msg_t);
220 DISSECTOR_ASSERT(trxmsg);
224 trxmsg->last = trxmsg;
227 m->trxs->last = m->trxs->last->next = trxmsg;
236 gcp_ctx_t* gcp_ctx(gcp_msg_t* m, gcp_trx_t* t, guint32 c_id, gboolean persistent) {
237 gcp_ctx_t* context = NULL;
238 gcp_ctx_t** context_p = NULL;
240 if ( !m || !t ) return NULL;
244 wmem_tree_key_t ctx_key[4];
245 wmem_tree_key_t trx_key[4];
247 ctx_key[0].length = 1;
248 ctx_key[0].key = &(m->hi_addr);
249 ctx_key[1].length = 1;
250 ctx_key[1].key = &(m->lo_addr);
251 ctx_key[2].length = 1;
252 ctx_key[2].key = &(c_id);
253 ctx_key[3].length = 0;
254 ctx_key[3].key = NULL;
256 trx_key[0].length = 1;
257 trx_key[0].key = &(m->hi_addr);
258 trx_key[1].length = 1;
259 trx_key[1].key = &(m->lo_addr);
260 trx_key[2].length = 1;
261 trx_key[2].key = &(t->id);
262 trx_key[3].length = 0;
263 trx_key[3].key = NULL;
266 if (( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
268 } if ((context_p = (gcp_ctx_t **)wmem_tree_lookup32_array(ctxs,ctx_key))) {
269 context = *context_p;
272 if (context->initial->framenum <= m->framenum) {
275 } while(( context = context->prev ));
277 DISSECTOR_ASSERT(! "a context should exist");
280 if (c_id == CHOOSE_CONTEXT) {
281 if (! ( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key))) {
282 context = wmem_new(wmem_file_scope(), gcp_ctx_t);
283 context->initial = m;
284 context->cmds = NULL;
286 context->terms.last = &(context->terms);
287 context->terms.next = NULL;
288 context->terms.term = NULL;
290 wmem_tree_insert32_array(ctxs_by_trx,trx_key,context);
293 if (( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
294 if (( context_p = (gcp_ctx_t **)wmem_tree_lookup32_array(ctxs,ctx_key) )) {
295 if (context != *context_p) {
296 if(context->id != CHOOSE_CONTEXT) {
297 context = wmem_new(wmem_file_scope(), gcp_ctx_t);
299 context->initial = m;
301 context->cmds = NULL;
302 context->terms.last = &(context->terms);
303 context->terms.next = NULL;
304 context->terms.term = NULL;
306 context->prev = *context_p;
307 *context_p = context;
310 context_p = wmem_new(wmem_file_scope(), gcp_ctx_t*);
311 *context_p = context;
312 context->initial = m;
314 wmem_tree_insert32_array(ctxs,ctx_key,context_p);
316 } else if (! ( context_p = (gcp_ctx_t**)wmem_tree_lookup32_array(ctxs,ctx_key) )) {
317 context = wmem_new(wmem_file_scope(), gcp_ctx_t);
318 context->initial = m;
320 context->cmds = NULL;
321 context->terms.last = &(context->terms);
322 context->terms.next = NULL;
323 context->terms.term = NULL;
325 context_p = wmem_new(wmem_file_scope(), gcp_ctx_t*);
326 *context_p = context;
327 wmem_tree_insert32_array(ctxs,ctx_key,context_p);
329 context = *context_p;
334 context = wmem_new(wmem_packet_scope(), gcp_ctx_t);
335 context->initial = m;
336 context->cmds = NULL;
338 context->terms.last = &(context->terms);
339 context->terms.next = NULL;
340 context->terms.term = NULL;
346 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) {
348 gcp_cmd_msg_t* cmdtrx;
349 gcp_cmd_msg_t* cmdctx;
351 if ( !m || !t || !c ) return NULL;
355 DISSECTOR_ASSERT(t->cmds != NULL);
357 for (cmdctx = t->cmds; cmdctx; cmdctx = cmdctx->next) {
359 if (cmd->msg == m && cmd->offset == offset) {
364 DISSECTOR_ASSERT(!"called for a command that does not exist!");
368 cmd = wmem_new(wmem_file_scope(), gcp_cmd_t);
369 cmdtrx = wmem_new(wmem_file_scope(), gcp_cmd_msg_t);
370 cmdctx = wmem_new(wmem_file_scope(), gcp_cmd_msg_t);
373 cmd = wmem_new(wmem_packet_scope(), gcp_cmd_t);
374 cmdtrx = wmem_new(wmem_packet_scope(), gcp_cmd_msg_t);
375 cmdctx = wmem_new(wmem_packet_scope(), gcp_cmd_msg_t);
379 cmd->offset = offset;
380 cmd->terms.term = NULL;
381 cmd->terms.next = NULL;
382 cmd->terms.last = &(cmd->terms);
389 cmdctx->cmd = cmdtrx->cmd = cmd;
390 cmdctx->next = cmdtrx->next = NULL;
391 cmdctx->last = cmdtrx->last = NULL;
394 t->cmds->last->next = cmdtrx;
395 t->cmds->last = cmdtrx;
398 t->cmds->last = cmdtrx;
402 c->cmds->last->next = cmdctx;
403 c->cmds->last = cmdctx;
406 c->cmds->last = cmdctx;
413 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) {
417 static gcp_term_t all_terms = {"$",(const guint8*)"",1,GCP_TERM_TYPE_UNKNOWN,NULL,NULL,NULL};
419 if ( !c ) return NULL;
421 if ( wildcard == GCP_WILDCARD_CHOOSE) {
426 if ( c->msg->committed ) {
427 if (wildcard == GCP_WILDCARD_ALL) {
428 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
429 /* XXX not handling more wilcards in one msg */
430 if ( ct->term->start == m ) {
436 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
437 if ( g_str_equal(ct->term->str,t->str) ) {
445 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
446 if ( g_str_equal(ct->term->str,t->str) || ct->term->start == m) {
453 if (wildcard == GCP_WILDCARD_ALL) {
454 ct = wmem_new(wmem_file_scope(), gcp_terms_t);
456 ct->term = wmem_new0(wmem_file_scope(), gcp_term_t);
460 ct->term->buffer = NULL;
463 c->terms.last = c->terms.last->next = ct;
465 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
466 ct2->term = ct->term;
468 c->ctx->terms.last->next = ct2;
469 c->ctx->terms.last = ct2;
473 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
474 /* XXX not handling more wilcards in one msg */
475 if ( ct->term->buffer == NULL && tr->cmds->cmd->msg == ct->term->start ) {
476 ct->term->str = wmem_strdup(wmem_file_scope(), t->str);
477 ct->term->buffer = (const guint8 *)wmem_memdup(wmem_file_scope(), t->buffer,t->len);
478 ct->term->len = t->len;
480 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
481 ct2->term = ct->term;
483 c->terms.last = c->terms.last->next = ct2;
488 if ( g_str_equal(ct->term->str,t->str) ) {
489 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
490 ct2->term = ct->term;
492 c->terms.last = c->terms.last->next = ct2;
498 ct = wmem_new(wmem_file_scope(), gcp_terms_t);
500 ct->term = wmem_new0(wmem_file_scope(), gcp_term_t);
503 ct->term->str = wmem_strdup(wmem_file_scope(), t->str);
504 ct->term->buffer = (const guint8 *)wmem_memdup(wmem_file_scope(), t->buffer,t->len);
505 ct->term->len = t->len;
507 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
508 ct2->term = ct->term;
510 c->terms.last = c->terms.last->next = ct2;
512 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
513 ct2->term = ct->term;
515 c->ctx->terms.last = c->ctx->terms.last->next = ct2;
520 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
521 ct2->term = ct->term;
523 c->terms.last = c->terms.last->next = ct2;
527 DISSECTOR_ASSERT_NOT_REACHED();
530 ct = wmem_new(wmem_packet_scope(), gcp_terms_t);
533 c->terms.last = c->terms.last->next = ct;
540 const gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent) {
544 if ( !c ) return "-";
550 case GCP_CMD_ADD_REQ:
553 case GCP_CMD_MOVE_REQ:
556 case GCP_CMD_MOD_REQ:
559 case GCP_CMD_SUB_REQ:
562 case GCP_CMD_AUDITCAP_REQ:
565 case GCP_CMD_AUDITVAL_REQ:
568 case GCP_CMD_NOTIFY_REQ:
571 case GCP_CMD_SVCCHG_REQ:
574 case GCP_CMD_TOPOLOGY_REQ:
577 case GCP_CMD_CTX_ATTR_AUDIT_REQ:
578 s = "CtxAttribAuditReq {";
580 case GCP_CMD_ADD_REPLY:
583 case GCP_CMD_MOVE_REPLY:
586 case GCP_CMD_MOD_REPLY:
589 case GCP_CMD_SUB_REPLY:
592 case GCP_CMD_AUDITCAP_REPLY:
593 s = "AuditCapReply {";
595 case GCP_CMD_AUDITVAL_REPLY:
596 s = "AuditValReply {";
598 case GCP_CMD_NOTIFY_REPLY:
601 case GCP_CMD_SVCCHG_REPLY:
604 case GCP_CMD_TOPOLOGY_REPLY:
605 s = "TopologyReply {";
610 case GCP_CMD_OTHER_REQ:
618 for (term = c->terms.next; term; term = term->next) {
619 s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,term->term->str);
623 s = wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s,c->error);
626 s = wmem_strdup_printf(wmem_packet_scope(), "%s }", s);
629 if (! c->str) c->str = wmem_strdup(wmem_file_scope(), s);
637 static const gchar* gcp_trx_to_str(gcp_msg_t* m, gcp_trx_t* t, gboolean persistent) {
641 if ( !m || !t ) return "-";
643 s = wmem_strdup_printf(wmem_packet_scope(), "T %x { ",t->id);
646 if (t->cmds->cmd->ctx) {
647 s = wmem_strdup_printf(wmem_packet_scope(), "%s C %x {",s,t->cmds->cmd->ctx->id);
649 for (c = t->cmds; c; c = c->next) {
650 if (c->cmd->msg == m) {
651 s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,gcp_cmd_to_str(c->cmd,persistent));
655 s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,"}");
660 s = wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s,t->error);
663 return wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,"}");
666 const gchar* gcp_msg_to_str(gcp_msg_t* m, gboolean persistent) {
670 if ( !m ) return "-";
672 for (t = m->trxs; t; t = t->next) {
673 s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,gcp_trx_to_str(m,t->trx, persistent));
679 typedef struct _gcp_ctxs_t {
680 struct _gcp_ctx_t* ctx;
681 struct _gcp_ctxs_t* next;
684 /*static const gchar* trx_types[] = {"None","Req","Reply","Pending","Ack"};*/
686 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) {
688 gcp_ctxs_t contexts = {NULL,NULL};
689 gcp_ctxs_t* ctx_node;
693 for (t = m->trxs; t; t = t->next) {
694 for (c = t->trx->cmds; c; c = c->next) {
695 gcp_ctx_t* ctx = c->cmd->ctx;
697 for (ctx_node = contexts.next; ctx_node; ctx_node = ctx_node->next) {
698 if (ctx_node->ctx->id == ctx->id) {
704 ctx_node = wmem_new(wmem_packet_scope(), gcp_ctxs_t);
706 ctx_node->next = contexts.next;
707 contexts.next = ctx_node;
712 for (ctx_node = contexts.next; ctx_node; ctx_node = ctx_node->next) {
713 gcp_ctx_t* ctx = ctx_node->ctx;
714 proto_item* ctx_item = proto_tree_add_uint(gcp_tree,ids->hf.ctx,gcp_tvb,0,0,ctx->id);
715 proto_tree* ctx_tree = proto_item_add_subtree(ctx_item,ids->ett.ctx);
716 gcp_terms_t *ctx_term;
718 PROTO_ITEM_SET_GENERATED(ctx_item);
721 proto_item* history_item = proto_tree_add_text(ctx_tree,gcp_tvb,0,0,"[ Command History ]");
722 proto_tree* history_tree = proto_item_add_subtree(history_item,ids->ett.ctx_cmds);
724 for (c = ctx->cmds; c; c = c->next) {
725 proto_item* cmd_item = proto_tree_add_uint(history_tree,ids->hf.ctx_cmd,gcp_tvb,0,0,c->cmd->msg->framenum);
726 if (c->cmd->str) proto_item_append_text(cmd_item," %s ",c->cmd->str);
727 PROTO_ITEM_SET_GENERATED(cmd_item);
729 expert_add_info(pinfo, cmd_item, command_err);
734 if (( ctx_term = ctx->terms.next )) {
735 proto_item* terms_item = proto_tree_add_text(ctx_tree,gcp_tvb,0,0,"[ Terminations Used ]");
736 proto_tree* terms_tree = proto_item_add_subtree(terms_item,ids->ett.ctx_terms);
738 for (; ctx_term; ctx_term = ctx_term->next ) {
739 if ( ctx_term->term && ctx_term->term->str) {
740 proto_item* pi = proto_tree_add_string(terms_tree,ids->hf.ctx_term,gcp_tvb,0,0,ctx_term->term->str);
741 proto_tree* term_tree = proto_item_add_subtree(pi,ids->ett.ctx_term);
743 PROTO_ITEM_SET_GENERATED(pi);
745 if (ctx_term->term->type) {
746 pi = proto_tree_add_uint(term_tree,ids->hf.ctx_term_type,gcp_tvb,0,0,ctx_term->term->type);
747 PROTO_ITEM_SET_GENERATED(pi);
750 if (ctx_term->term->bir) {
751 pi = proto_tree_add_string(term_tree,ids->hf.ctx_term_bir,gcp_tvb,0,0,ctx_term->term->bir);
752 PROTO_ITEM_SET_GENERATED(pi);
755 if (ctx_term->term->nsap) {
756 pi = proto_tree_add_string(term_tree,ids->hf.ctx_term_nsap,gcp_tvb,0,0,ctx_term->term->nsap);
757 PROTO_ITEM_SET_GENERATED(pi);
760 if (ctx_term->term->bir && ctx_term->term->nsap) {
761 gchar* tmp_key = wmem_strdup_printf(wmem_packet_scope(), "%s:%s",ctx_term->term->nsap,ctx_term->term->bir);
762 gchar* key = g_ascii_strdown(tmp_key, -1);
763 alcap_tree_from_bearer_key(term_tree, gcp_tvb, pinfo, key);
773 * Editor modelines - http://www.wireshark.org/tools/modelines.html
778 * indent-tabs-mode: nil
781 * vi: set shiftwidth=4 tabstop=8 expandtab:
782 * :indentSize=4:tabSize=8:noTabs=true: