Witness: add pidl output
[wireshark-wip.git] / epan / gcp.c
blob5c6ca7327fad8ea628de03674ce5e257282c24e4
1 /*
2 * gcp.c
3 * Gateway Control Protocol -- Context Tracking
5 * $Id$
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.
27 * TO DO:
28 * - handle text-encoded termination wildcards adequtelly
29 * - avoid persistent tracking of NULL and ALL contexts
32 #include "config.h"
34 #include <epan/emem.h>
36 #include "gcp.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"},
64 { 0, NULL }
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" },
73 { 0, NULL }
77 void gcp_init(void) {
78 static gboolean gcp_initialized = FALSE;
80 if (gcp_initialized)
81 return;
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) {
91 gcp_msg_t* m;
92 guint32 framenum = (guint32)pinfo->fd->num;
93 guint32 offset = (guint32)o;
94 address* src = &(pinfo->src);
95 address* dst = &(pinfo->dst);
96 address* lo_addr;
97 address* hi_addr;
99 if (keep_persistent_data) {
100 wmem_tree_key_t key[] = {
101 {1,&(framenum)},
102 {1,&offset},
103 {0,NULL}
106 if (( m = (gcp_msg_t *)wmem_tree_lookup32_array(msgs,key) )) {
107 m->commited = TRUE;
108 return m;
109 } else {
110 m = wmem_new(wmem_file_scope(), gcp_msg_t);
111 m->framenum = framenum;
112 m->time = pinfo->fd->abs_ts;
113 m->trxs = NULL;
114 m->commited = FALSE;
116 wmem_tree_insert32_array(msgs,key,m);
118 } else {
119 m = wmem_new0(wmem_packet_scope(), gcp_msg_t);
120 m->framenum = framenum;
121 m->trxs = NULL;
122 m->commited = FALSE;
125 if (CMP_ADDRESS(src, dst) < 0) {
126 lo_addr = src;
127 hi_addr = dst;
128 } else {
129 lo_addr = dst;
130 hi_addr = src;
133 switch(lo_addr->type) {
134 case AT_NONE:
135 m->lo_addr = 0;
136 m->hi_addr = 0;
137 break;
138 case AT_IPv4:
139 memcpy((guint8*)&(m->hi_addr),hi_addr->data,4);
140 memcpy((guint8*)&(m->lo_addr),lo_addr->data,4);
141 break;
142 case AT_SS7PC:
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);
145 break;
146 default:
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));
150 break;
153 return m;
156 gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean keep_persistent_data) {
157 gcp_trx_t* t = NULL;
158 gcp_trx_msg_t* trxmsg;
160 if ( !m ) return NULL;
162 if (keep_persistent_data) {
163 if (m->commited) {
165 for ( trxmsg = m->trxs; trxmsg; trxmsg = trxmsg->next) {
166 if (trxmsg->trx && trxmsg->trx->id == t_id) {
167 return trxmsg->trx;
170 DISSECTOR_ASSERT_NOT_REACHED();
171 } else {
172 wmem_tree_key_t key[] = {
173 {1,&(m->hi_addr)},
174 {1,&(m->lo_addr)},
175 {1,&(t_id)},
176 {0,NULL}
179 trxmsg = wmem_new(wmem_file_scope(), gcp_trx_msg_t);
180 t = (gcp_trx_t *)wmem_tree_lookup32_array(trxs,key);
182 if (!t) {
183 t = wmem_new(wmem_file_scope(), gcp_trx_t);
184 t->initial = m;
185 t->id = t_id;
186 t->type = type;
187 t->pendings = 0;
188 t->error = 0;
189 t->cmds = NULL;
191 wmem_tree_insert32_array(trxs,key,t);
194 /* XXX: request, reply and ack + point to frames where they are */
195 switch ( type ) {
196 case GCP_TRX_PENDING:
197 t->pendings++;
198 break;
199 default:
200 break;
204 } else {
205 t = wmem_new(wmem_packet_scope(), gcp_trx_t);
206 trxmsg = wmem_new(wmem_packet_scope(), gcp_trx_msg_t);
207 t->initial = NULL;
208 t->id = t_id;
209 t->type = type;
210 t->pendings = 0;
211 t->error = 0;
212 t->cmds = NULL;
215 DISSECTOR_ASSERT(trxmsg);
217 trxmsg->trx = t;
218 trxmsg->next = NULL;
219 trxmsg->last = trxmsg;
221 if (m->trxs) {
222 m->trxs->last = m->trxs->last->next = trxmsg;
223 } else {
224 m->trxs = trxmsg;
227 return t;
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;
237 if (persistent) {
239 wmem_tree_key_t ctx_key[] = {
240 {1,&(m->hi_addr)},
241 {1,&(m->lo_addr)},
242 {1,&(c_id)},
243 {0,NULL}
246 wmem_tree_key_t trx_key[] = {
247 {1,&(m->hi_addr)},
248 {1,&(m->lo_addr)},
249 {1,&(t->id)},
250 {0,NULL}
253 if (m->commited) {
254 if (( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
255 return context;
256 } if ((context_p = (gcp_ctx_t **)wmem_tree_lookup32_array(ctxs,ctx_key))) {
257 context = *context_p;
259 do {
260 if (context->initial->framenum <= m->framenum) {
261 return context;
263 } while(( context = context->prev ));
265 DISSECTOR_ASSERT(! "a context should exist");
267 } else {
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;
273 context->id = c_id;
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);
280 } else {
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;
288 context->id = c_id;
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;
297 } else {
298 context_p = wmem_new(wmem_file_scope(), gcp_ctx_t*);
299 *context_p = context;
300 context->initial = m;
301 context->id = c_id;
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;
307 context->id = c_id;
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);
316 } else {
317 context = *context_p;
321 } else {
322 context = wmem_new(wmem_packet_scope(), gcp_ctx_t);
323 context->initial = m;
324 context->cmds = NULL;
325 context->id = c_id;
326 context->terms.last = &(context->terms);
327 context->terms.next = NULL;
328 context->terms.term = NULL;
331 return context;
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) {
335 gcp_cmd_t* cmd;
336 gcp_cmd_msg_t* cmdtrx;
337 gcp_cmd_msg_t* cmdctx;
339 if ( !m || !t || !c ) return NULL;
341 if (persistent) {
342 if (m->commited) {
343 DISSECTOR_ASSERT(t->cmds != NULL);
345 for (cmdctx = t->cmds; cmdctx; cmdctx = cmdctx->next) {
346 cmd = cmdctx->cmd;
347 if (cmd->msg == m && cmd->offset == offset) {
348 return cmd;
352 DISSECTOR_ASSERT(!"called for a command that does not exist!");
354 return NULL;
355 } else {
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);
360 } else {
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);
366 cmd->type = type;
367 cmd->offset = offset;
368 cmd->terms.term = NULL;
369 cmd->terms.next = NULL;
370 cmd->terms.last = &(cmd->terms);
371 cmd->str = NULL;
372 cmd->msg = m;
373 cmd->trx = t;
374 cmd->ctx = c;
375 cmd->error = 0;
377 cmdctx->cmd = cmdtrx->cmd = cmd;
378 cmdctx->next = cmdtrx->next = NULL;
379 cmdctx->last = cmdtrx->last = NULL;
381 if (t->cmds) {
382 t->cmds->last->next = cmdtrx;
383 t->cmds->last = cmdtrx;
384 } else {
385 t->cmds = cmdtrx;
386 t->cmds->last = cmdtrx;
389 if (c->cmds) {
390 c->cmds->last->next = cmdctx;
391 c->cmds->last = cmdctx;
392 } else {
393 c->cmds = cmdctx;
394 c->cmds->last = cmdctx;
397 return cmd;
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) {
402 gcp_terms_t* ct;
403 gcp_terms_t* ct2;
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) {
410 return &all_terms;
413 if (persistent) {
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 ) {
419 return ct->term;
422 return NULL;
423 } else {
424 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
425 if ( g_str_equal(ct->term->str,t->str) ) {
426 return ct->term;
429 return NULL;
431 } else {
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) {
435 break;
439 if ( ! ct ) {
441 if (wildcard == GCP_WILDCARD_ALL) {
442 ct = wmem_new(wmem_file_scope(), gcp_terms_t);
443 ct->next = NULL;
444 ct->term = wmem_new0(wmem_file_scope(), gcp_term_t);
446 ct->term->start = m;
447 ct->term->str = "*";
448 ct->term->buffer = NULL;
449 ct->term->len = 0;
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;
459 return ct->term;
460 } else {
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;
473 return ct->term;
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;
482 return ct->term;
486 ct = wmem_new(wmem_file_scope(), gcp_terms_t);
487 ct->next = NULL;
488 ct->term = wmem_new0(wmem_file_scope(), gcp_term_t);
490 ct->term->start = m;
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;
505 return ct->term;
507 } else {
508 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
509 ct2->term = ct->term;
511 c->terms.last = c->terms.last->next = ct2;
512 return ct->term;
515 DISSECTOR_ASSERT_NOT_REACHED();
517 } else {
518 ct = wmem_new(wmem_packet_scope(), gcp_terms_t);
519 ct->term = t;
520 ct->next = NULL;
521 c->terms.last = c->terms.last->next = ct;
523 return t;
528 const gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent) {
529 const gchar* s;
530 gcp_terms_t* term;
532 if ( !c ) return "-";
534 switch (c->type) {
535 case GCP_CMD_NONE:
536 return "-";
537 break;
538 case GCP_CMD_ADD_REQ:
539 s = "AddReq {";
540 break;
541 case GCP_CMD_MOVE_REQ:
542 s = "MoveReq {";
543 break;
544 case GCP_CMD_MOD_REQ:
545 s = "ModReq {";
546 break;
547 case GCP_CMD_SUB_REQ:
548 s = "SubReq {";
549 break;
550 case GCP_CMD_AUDITCAP_REQ:
551 s = "AuditCapReq {";
552 break;
553 case GCP_CMD_AUDITVAL_REQ:
554 s = "AuditValReq {";
555 break;
556 case GCP_CMD_NOTIFY_REQ:
557 s = "NotifyReq {";
558 break;
559 case GCP_CMD_SVCCHG_REQ:
560 s = "SvcChgReq {";
561 break;
562 case GCP_CMD_TOPOLOGY_REQ:
563 s = "TopologyReq {";
564 break;
565 case GCP_CMD_CTX_ATTR_AUDIT_REQ:
566 s = "CtxAttribAuditReq {";
567 break;
568 case GCP_CMD_ADD_REPLY:
569 s = "AddReply {";
570 break;
571 case GCP_CMD_MOVE_REPLY:
572 s = "MoveReply {";
573 break;
574 case GCP_CMD_MOD_REPLY:
575 s = "ModReply {";
576 break;
577 case GCP_CMD_SUB_REPLY:
578 s = "SubReply {";
579 break;
580 case GCP_CMD_AUDITCAP_REPLY:
581 s = "AuditCapReply {";
582 break;
583 case GCP_CMD_AUDITVAL_REPLY:
584 s = "AuditValReply {";
585 break;
586 case GCP_CMD_NOTIFY_REPLY:
587 s = "NotifyReply {";
588 break;
589 case GCP_CMD_SVCCHG_REPLY:
590 s = "SvcChgReply {";
591 break;
592 case GCP_CMD_TOPOLOGY_REPLY:
593 s = "TopologyReply {";
594 break;
595 case GCP_CMD_REPLY:
596 s = "ActionReply {";
597 break;
598 case GCP_CMD_OTHER_REQ:
599 s = "Request {";
600 break;
601 default:
602 s = "-";
603 break;
606 for (term = c->terms.next; term; term = term->next) {
607 s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,term->term->str);
610 if (c->error) {
611 s = wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s,c->error);
614 s = wmem_strdup_printf(wmem_packet_scope(), "%s }", s);
616 if (persistent) {
617 if (! c->str) c->str = wmem_strdup(wmem_file_scope(), s);
618 } else {
619 c->str = s;
622 return s;
625 static const gchar* gcp_trx_to_str(gcp_msg_t* m, gcp_trx_t* t, gboolean persistent) {
626 gchar* s;
627 gcp_cmd_msg_t* c;
629 if ( !m || !t ) return "-";
631 s = wmem_strdup_printf(wmem_packet_scope(), "T %x { ",t->id);
633 if (t->cmds) {
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,"}");
647 if (t->error) {
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) {
655 gcp_trx_msg_t* t;
656 const gchar* s = "";
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));
664 return s;
667 typedef struct _gcp_ctxs_t {
668 struct _gcp_ctx_t* ctx;
669 struct _gcp_ctxs_t* next;
670 } gcp_ctxs_t;
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) {
675 gcp_trx_msg_t* t;
676 gcp_ctxs_t contexts = {NULL,NULL};
677 gcp_ctxs_t* ctx_node;
678 gcp_cmd_msg_t* c;
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) {
687 break;
691 if (! ctx_node) {
692 ctx_node = wmem_new(wmem_packet_scope(), gcp_ctxs_t);
693 ctx_node->ctx = ctx;
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);
708 if (ctx->cmds) {
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);
716 if (c->cmd->error) {
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);
752 g_free(key);