4f5287f3c1160cfab16c48826aa3a0da35a0956f
[metze/wireshark/wip.git] / epan / gcp.c
1 /*
2  * gcp.c
3  * Gateway Control Protocol -- Context Tracking
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
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.
13  *
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.
18  *
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.
22  */
23
24  /*
25   * TO DO:
26   *  - handle text-encoded termination wildcards adequtelly
27   *  - avoid persistent tracking of NULL and ALL contexts
28   */
29
30 #include "config.h"
31
32 #include <epan/emem.h>
33
34 #include "gcp.h"
35
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;
40
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"},
62     { 0, NULL }
63 };
64
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" },
71     { 0, NULL }
72 };
73
74
75 void gcp_init(void) {
76     static gboolean gcp_initialized = FALSE;
77
78     if (gcp_initialized)
79         return;
80
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;
86 }
87
88 gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean keep_persistent_data) {
89     gcp_msg_t* m;
90     guint32 framenum = (guint32)pinfo->fd->num;
91     guint32 offset = (guint32)o;
92     address* src = &(pinfo->src);
93     address* dst = &(pinfo->dst);
94     address* lo_addr;
95     address* hi_addr;
96
97     if (keep_persistent_data) {
98         wmem_tree_key_t key[3];
99
100         key[0].length = 1;
101         key[0].key = &(framenum);
102         key[1].length = 1;
103         key[1].key = &offset;
104         key[2].length = 0;
105         key[2].key =NULL;
106
107         if (( m = (gcp_msg_t *)wmem_tree_lookup32_array(msgs,key) )) {
108             m->committed = TRUE;
109             return m;
110         } else {
111             m = wmem_new(wmem_file_scope(), gcp_msg_t);
112             m->framenum = framenum;
113             m->time = pinfo->fd->abs_ts;
114             m->trxs = NULL;
115             m->committed = FALSE;
116
117             wmem_tree_insert32_array(msgs,key,m);
118         }
119     } else {
120         m = wmem_new0(wmem_packet_scope(), gcp_msg_t);
121         m->framenum = framenum;
122         m->trxs = NULL;
123         m->committed = FALSE;
124     }
125
126     if (CMP_ADDRESS(src, dst) < 0)  {
127         lo_addr = src;
128         hi_addr = dst;
129     } else {
130         lo_addr = dst;
131         hi_addr = src;
132     }
133
134     switch(lo_addr->type) {
135         case AT_NONE:
136             m->lo_addr = 0;
137             m->hi_addr = 0;
138             break;
139         case AT_IPv4:
140             memcpy((guint8*)&(m->hi_addr),hi_addr->data,4);
141             memcpy((guint8*)&(m->lo_addr),lo_addr->data,4);
142             break;
143         case AT_SS7PC:
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);
146             break;
147         default:
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));
151         break;
152     }
153
154     return m;
155 }
156
157 gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean keep_persistent_data) {
158     gcp_trx_t* t = NULL;
159     gcp_trx_msg_t* trxmsg;
160
161     if ( !m ) return NULL;
162
163     if (keep_persistent_data) {
164         if (m->committed) {
165
166             for ( trxmsg = m->trxs; trxmsg; trxmsg = trxmsg->next) {
167                 if (trxmsg->trx && trxmsg->trx->id == t_id) {
168                     return trxmsg->trx;
169                 }
170             }
171             DISSECTOR_ASSERT_NOT_REACHED();
172         } else {
173             wmem_tree_key_t key[4];
174
175             key[0].length = 1;
176             key[0].key = &(m->hi_addr);
177             key[1].length = 1;
178             key[1].key = &(m->lo_addr);
179             key[2].length = 1;
180             key[2].key = &(t_id);
181             key[3].length = 0;
182             key[3].key = NULL;
183
184             trxmsg = wmem_new(wmem_file_scope(), gcp_trx_msg_t);
185             t = (gcp_trx_t *)wmem_tree_lookup32_array(trxs,key);
186
187             if (!t) {
188                 t = wmem_new(wmem_file_scope(), gcp_trx_t);
189                 t->initial = m;
190                 t->id = t_id;
191                 t->type = type;
192                 t->pendings = 0;
193                 t->error = 0;
194                 t->cmds = NULL;
195
196                 wmem_tree_insert32_array(trxs,key,t);
197             }
198
199             /* XXX: request, reply and ack + point to frames where they are */
200             switch ( type ) {
201                 case GCP_TRX_PENDING:
202                     t->pendings++;
203                     break;
204                 default:
205                     break;
206             }
207
208         }
209     } else {
210         t = wmem_new(wmem_packet_scope(), gcp_trx_t);
211         trxmsg = wmem_new(wmem_packet_scope(), gcp_trx_msg_t);
212         t->initial = NULL;
213         t->id = t_id;
214         t->type = type;
215         t->pendings = 0;
216         t->error = 0;
217         t->cmds = NULL;
218     }
219
220     DISSECTOR_ASSERT(trxmsg);
221
222     trxmsg->trx = t;
223     trxmsg->next = NULL;
224     trxmsg->last = trxmsg;
225
226     if (m->trxs) {
227         m->trxs->last = m->trxs->last->next = trxmsg;
228     } else {
229         m->trxs = trxmsg;
230     }
231
232     return t;
233 }
234
235
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;
239
240     if ( !m || !t ) return NULL;
241
242     if (persistent) {
243
244         wmem_tree_key_t ctx_key[4];
245         wmem_tree_key_t trx_key[4];
246
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;
255
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;
264
265         if (m->committed) {
266             if (( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
267                 return context;
268             } if ((context_p = (gcp_ctx_t **)wmem_tree_lookup32_array(ctxs,ctx_key))) {
269                 context = *context_p;
270
271                 do {
272                     if (context->initial->framenum <= m->framenum) {
273                         return context;
274                     }
275                 } while(( context = context->prev ));
276
277                 DISSECTOR_ASSERT(! "a context should exist");
278             }
279         } else {
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;
285                     context->id = c_id;
286                     context->terms.last = &(context->terms);
287                     context->terms.next = NULL;
288                     context->terms.term = NULL;
289
290                     wmem_tree_insert32_array(ctxs_by_trx,trx_key,context);
291                 }
292             } else {
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);
298                             }
299                             context->initial = m;
300                             context->id = c_id;
301                             context->cmds = NULL;
302                             context->terms.last = &(context->terms);
303                             context->terms.next = NULL;
304                             context->terms.term = NULL;
305
306                             context->prev = *context_p;
307                             *context_p = context;
308                         }
309                     } else {
310                         context_p = wmem_new(wmem_file_scope(), gcp_ctx_t*);
311                         *context_p = context;
312                         context->initial = m;
313                         context->id = c_id;
314                         wmem_tree_insert32_array(ctxs,ctx_key,context_p);
315                     }
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;
319                     context->id = c_id;
320                     context->cmds = NULL;
321                     context->terms.last = &(context->terms);
322                     context->terms.next = NULL;
323                     context->terms.term = NULL;
324
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);
328                 } else {
329                     context = *context_p;
330                 }
331             }
332         }
333     } else {
334         context = wmem_new(wmem_packet_scope(), gcp_ctx_t);
335         context->initial = m;
336         context->cmds = NULL;
337         context->id = c_id;
338         context->terms.last = &(context->terms);
339         context->terms.next = NULL;
340         context->terms.term = NULL;
341     }
342
343     return context;
344 }
345
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) {
347     gcp_cmd_t* cmd;
348     gcp_cmd_msg_t* cmdtrx;
349     gcp_cmd_msg_t* cmdctx;
350
351     if ( !m || !t || !c ) return NULL;
352
353     if (persistent) {
354         if (m->committed) {
355             DISSECTOR_ASSERT(t->cmds != NULL);
356
357             for (cmdctx = t->cmds; cmdctx; cmdctx = cmdctx->next) {
358                 cmd = cmdctx->cmd;
359                 if (cmd->msg == m && cmd->offset == offset) {
360                     return cmd;
361                 }
362             }
363
364             DISSECTOR_ASSERT(!"called for a command that does not exist!");
365
366             return NULL;
367         } else {
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);
371         }
372     } else {
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);
376     }
377
378     cmd->type = type;
379     cmd->offset = offset;
380     cmd->terms.term = NULL;
381     cmd->terms.next = NULL;
382     cmd->terms.last = &(cmd->terms);
383     cmd->str = NULL;
384     cmd->msg = m;
385     cmd->trx = t;
386     cmd->ctx = c;
387     cmd->error = 0;
388
389     cmdctx->cmd = cmdtrx->cmd = cmd;
390     cmdctx->next =  cmdtrx->next = NULL;
391     cmdctx->last = cmdtrx->last = NULL;
392
393     if (t->cmds) {
394         t->cmds->last->next = cmdtrx;
395         t->cmds->last = cmdtrx;
396     } else {
397         t->cmds = cmdtrx;
398         t->cmds->last = cmdtrx;
399     }
400
401     if (c->cmds) {
402         c->cmds->last->next = cmdctx;
403         c->cmds->last = cmdctx;
404     } else {
405         c->cmds = cmdctx;
406         c->cmds->last = cmdctx;
407     }
408
409     return cmd;
410 }
411
412
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) {
414     gcp_terms_t* ct;
415     gcp_terms_t* ct2;
416
417     static gcp_term_t all_terms = {"$",(const guint8*)"",1,GCP_TERM_TYPE_UNKNOWN,NULL,NULL,NULL};
418
419     if ( !c ) return NULL;
420
421     if ( wildcard == GCP_WILDCARD_CHOOSE) {
422         return &all_terms;
423     }
424
425     if (persistent) {
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 ) {
431                         return ct->term;
432                     }
433                 }
434                 return NULL;
435             } else {
436                 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
437                     if ( g_str_equal(ct->term->str,t->str) ) {
438                         return ct->term;
439                     }
440                 }
441                 return NULL;
442             }
443         } else {
444
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) {
447                     break;
448                 }
449             }
450
451             if ( ! ct ) {
452
453                 if (wildcard == GCP_WILDCARD_ALL) {
454                     ct = wmem_new(wmem_file_scope(), gcp_terms_t);
455                     ct->next = NULL;
456                     ct->term = wmem_new0(wmem_file_scope(), gcp_term_t);
457
458                     ct->term->start = m;
459                     ct->term->str = "*";
460                     ct->term->buffer = NULL;
461                     ct->term->len = 0;
462
463                     c->terms.last = c->terms.last->next = ct;
464
465                     ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
466                     ct2->term = ct->term;
467
468                     c->ctx->terms.last->next = ct2;
469                     c->ctx->terms.last = ct2;
470
471                     return ct->term;
472                 } else {
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;
479
480                             ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
481                             ct2->term = ct->term;
482
483                             c->terms.last = c->terms.last->next = ct2;
484
485                             return ct->term;
486                         }
487
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;
491
492                             c->terms.last = c->terms.last->next = ct2;
493
494                             return ct->term;
495                         }
496                     }
497
498                     ct = wmem_new(wmem_file_scope(), gcp_terms_t);
499                     ct->next = NULL;
500                     ct->term = wmem_new0(wmem_file_scope(), gcp_term_t);
501
502                     ct->term->start = m;
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;
506
507                     ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
508                     ct2->term = ct->term;
509
510                     c->terms.last = c->terms.last->next = ct2;
511
512                     ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
513                     ct2->term = ct->term;
514
515                     c->ctx->terms.last = c->ctx->terms.last->next = ct2;
516
517                     return ct->term;
518                 }
519             } else {
520                 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
521                 ct2->term = ct->term;
522
523                 c->terms.last = c->terms.last->next = ct2;
524                 return ct->term;
525             }
526
527             DISSECTOR_ASSERT_NOT_REACHED();
528         }
529     } else {
530         ct = wmem_new(wmem_packet_scope(), gcp_terms_t);
531         ct->term = t;
532         ct->next = NULL;
533         c->terms.last = c->terms.last->next = ct;
534
535         return t;
536     }
537
538 }
539
540 const gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent) {
541     const gchar* s;
542     gcp_terms_t* term;
543
544     if ( !c ) return "-";
545
546     switch (c->type) {
547         case GCP_CMD_NONE:
548             return "-";
549             break;
550         case GCP_CMD_ADD_REQ:
551             s = "AddReq {";
552             break;
553         case GCP_CMD_MOVE_REQ:
554             s = "MoveReq {";
555             break;
556         case GCP_CMD_MOD_REQ:
557             s = "ModReq {";
558             break;
559         case GCP_CMD_SUB_REQ:
560             s = "SubReq {";
561             break;
562         case GCP_CMD_AUDITCAP_REQ:
563             s = "AuditCapReq {";
564             break;
565         case GCP_CMD_AUDITVAL_REQ:
566             s = "AuditValReq {";
567             break;
568         case GCP_CMD_NOTIFY_REQ:
569             s = "NotifyReq {";
570             break;
571         case GCP_CMD_SVCCHG_REQ:
572             s = "SvcChgReq {";
573             break;
574         case GCP_CMD_TOPOLOGY_REQ:
575             s = "TopologyReq {";
576             break;
577         case GCP_CMD_CTX_ATTR_AUDIT_REQ:
578             s = "CtxAttribAuditReq {";
579             break;
580         case GCP_CMD_ADD_REPLY:
581             s = "AddReply {";
582             break;
583         case GCP_CMD_MOVE_REPLY:
584             s = "MoveReply {";
585             break;
586         case GCP_CMD_MOD_REPLY:
587             s = "ModReply {";
588             break;
589         case GCP_CMD_SUB_REPLY:
590             s = "SubReply {";
591             break;
592         case GCP_CMD_AUDITCAP_REPLY:
593             s = "AuditCapReply {";
594             break;
595         case GCP_CMD_AUDITVAL_REPLY:
596             s = "AuditValReply {";
597             break;
598         case GCP_CMD_NOTIFY_REPLY:
599             s = "NotifyReply {";
600             break;
601         case GCP_CMD_SVCCHG_REPLY:
602             s = "SvcChgReply {";
603             break;
604         case GCP_CMD_TOPOLOGY_REPLY:
605             s = "TopologyReply {";
606             break;
607         case GCP_CMD_REPLY:
608             s = "ActionReply {";
609             break;
610         case GCP_CMD_OTHER_REQ:
611             s = "Request {";
612             break;
613         default:
614             s = "-";
615             break;
616     }
617
618     for (term = c->terms.next; term; term = term->next) {
619         s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,term->term->str);
620     }
621
622     if (c->error) {
623         s = wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s,c->error);
624     }
625
626     s = wmem_strdup_printf(wmem_packet_scope(), "%s }", s);
627
628     if (persistent) {
629         if (! c->str) c->str = wmem_strdup(wmem_file_scope(), s);
630     } else {
631         c->str = s;
632     }
633
634     return s;
635 }
636
637 static const gchar* gcp_trx_to_str(gcp_msg_t* m, gcp_trx_t* t, gboolean persistent) {
638     gchar* s;
639     gcp_cmd_msg_t* c;
640
641     if ( !m || !t ) return "-";
642
643     s = wmem_strdup_printf(wmem_packet_scope(), "T %x { ",t->id);
644
645     if (t->cmds) {
646         if (t->cmds->cmd->ctx) {
647             s = wmem_strdup_printf(wmem_packet_scope(), "%s C %x {",s,t->cmds->cmd->ctx->id);
648
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));
652                 }
653             }
654
655             s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,"}");
656         }
657     }
658
659     if (t->error) {
660         s = wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s,t->error);
661     }
662
663     return wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,"}");
664 }
665
666 const gchar* gcp_msg_to_str(gcp_msg_t* m, gboolean persistent) {
667     gcp_trx_msg_t* t;
668     const gchar* s = "";
669
670     if ( !m ) return "-";
671
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));
674     }
675
676     return s;
677 }
678
679 typedef struct _gcp_ctxs_t {
680     struct _gcp_ctx_t* ctx;
681     struct _gcp_ctxs_t* next;
682 } gcp_ctxs_t;
683
684 /*static const gchar* trx_types[] = {"None","Req","Reply","Pending","Ack"};*/
685
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) {
687     gcp_trx_msg_t* t;
688     gcp_ctxs_t contexts = {NULL,NULL};
689     gcp_ctxs_t* ctx_node;
690     gcp_cmd_msg_t* c;
691
692
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;
696
697             for (ctx_node = contexts.next; ctx_node; ctx_node = ctx_node->next) {
698                 if (ctx_node->ctx->id == ctx->id) {
699                     break;
700                 }
701             }
702
703             if (! ctx_node) {
704                 ctx_node = wmem_new(wmem_packet_scope(), gcp_ctxs_t);
705                 ctx_node->ctx = ctx;
706                 ctx_node->next = contexts.next;
707                 contexts.next = ctx_node;
708             }
709         }
710     }
711
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;
717
718         PROTO_ITEM_SET_GENERATED(ctx_item);
719
720         if (ctx->cmds) {
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);
723
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);
728                 if (c->cmd->error) {
729                     expert_add_info(pinfo, cmd_item, command_err);
730                 }
731             }
732         }
733
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);
737
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);
742
743                     PROTO_ITEM_SET_GENERATED(pi);
744
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);
748                     }
749
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);
753                     }
754
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);
758                     }
759
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);
764                         g_free(key);
765                     }
766                 }
767             }
768         }
769     }
770 }
771
772 /*
773  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
774  *
775  * Local variables:
776  * c-basic-offset: 4
777  * tab-width: 8
778  * indent-tabs-mode: nil
779  * End:
780  *
781  * vi: set shiftwidth=4 tabstop=8 expandtab:
782  * :indentSize=4:tabSize=8:noTabs=true:
783  */