Include packet-dcerpc-witness.h, so it's in the source tarball.
[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 "gcp.h"
33
34 static wmem_tree_t* msgs = NULL;
35 static wmem_tree_t* trxs = NULL;
36 static wmem_tree_t* ctxs_by_trx = NULL;
37 static wmem_tree_t* ctxs = NULL;
38
39 const value_string gcp_cmd_type[] = {
40     { GCP_CMD_NONE,               "NoCommand"},
41     { GCP_CMD_ADD_REQ,            "addReq"},
42     { GCP_CMD_MOVE_REQ,           "moveReq"},
43     { GCP_CMD_MOD_REQ,            "modReq"},
44     { GCP_CMD_SUB_REQ,            "subtractReq"},
45     { GCP_CMD_AUDITCAP_REQ,       "auditCapRequest"},
46     { GCP_CMD_AUDITVAL_REQ,       "auditValueRequest"},
47     { GCP_CMD_NOTIFY_REQ,         "notifyReq"},
48     { GCP_CMD_SVCCHG_REQ,         "serviceChangeReq"},
49     { GCP_CMD_TOPOLOGY_REQ,       "topologyReq"},
50     { GCP_CMD_CTX_ATTR_AUDIT_REQ, "ctxAttrAuditReq"},
51     { GCP_CMD_ADD_REPLY,          "addReply"},
52     { GCP_CMD_MOVE_REPLY,         "moveReply"},
53     { GCP_CMD_MOD_REPLY,          "modReply"},
54     { GCP_CMD_SUB_REPLY,          "subtractReply"},
55     { GCP_CMD_AUDITCAP_REPLY,     "auditCapReply"},
56     { GCP_CMD_AUDITVAL_REPLY,     "auditValReply"},
57     { GCP_CMD_NOTIFY_REPLY,       "notifyReply"},
58     { GCP_CMD_SVCCHG_REPLY,       "serviceChangeReply"},
59     { GCP_CMD_TOPOLOGY_REPLY,     "topologyReply"},
60     { 0, NULL }
61 };
62
63 const value_string gcp_term_types[] = {
64     { GCP_TERM_TYPE_AAL1,        "aal1" },
65     { GCP_TERM_TYPE_AAL2,        "aal2" },
66     { GCP_TERM_TYPE_AAL1_STRUCT, "aal1struct" },
67     { GCP_TERM_TYPE_IP_RTP,      "ipRtp" },
68     { GCP_TERM_TYPE_TDM,         "tdm" },
69     { 0, NULL }
70 };
71
72
73 void gcp_init(void) {
74     static gboolean gcp_initialized = FALSE;
75
76     if (gcp_initialized)
77         return;
78
79     msgs = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
80     trxs = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
81     ctxs_by_trx = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
82     ctxs = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
83     gcp_initialized = TRUE;
84 }
85
86 gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean keep_persistent_data) {
87     gcp_msg_t* m;
88     guint32 framenum = (guint32)pinfo->fd->num;
89     guint32 offset = (guint32)o;
90     address* src = &(pinfo->src);
91     address* dst = &(pinfo->dst);
92     address* lo_addr;
93     address* hi_addr;
94
95     if (keep_persistent_data) {
96         wmem_tree_key_t key[3];
97
98         key[0].length = 1;
99         key[0].key = &(framenum);
100         key[1].length = 1;
101         key[1].key = &offset;
102         key[2].length = 0;
103         key[2].key =NULL;
104
105         if (( m = (gcp_msg_t *)wmem_tree_lookup32_array(msgs,key) )) {
106             m->committed = TRUE;
107             return m;
108         } else {
109             m = wmem_new(wmem_file_scope(), gcp_msg_t);
110             m->framenum = framenum;
111             m->time = pinfo->fd->abs_ts;
112             m->trxs = NULL;
113             m->committed = FALSE;
114
115             wmem_tree_insert32_array(msgs,key,m);
116         }
117     } else {
118         m = wmem_new0(wmem_packet_scope(), gcp_msg_t);
119         m->framenum = framenum;
120         m->trxs = NULL;
121         m->committed = FALSE;
122     }
123
124     if (cmp_address(src, dst) < 0)  {
125         lo_addr = src;
126         hi_addr = dst;
127     } else {
128         lo_addr = dst;
129         hi_addr = src;
130     }
131
132     switch(lo_addr->type) {
133         case AT_NONE:
134             m->lo_addr = 0;
135             m->hi_addr = 0;
136             break;
137         case AT_IPv4:
138             memcpy((guint8*)&(m->hi_addr),hi_addr->data,4);
139             memcpy((guint8*)&(m->lo_addr),lo_addr->data,4);
140             break;
141         case AT_SS7PC:
142             m->hi_addr = mtp3_pc_hash((const mtp3_addr_pc_t *)hi_addr->data);
143             m->lo_addr = mtp3_pc_hash((const mtp3_addr_pc_t *)lo_addr->data);
144             break;
145         default:
146             /* XXX: heuristic and error prone */
147             m->hi_addr = g_str_hash(address_to_str(wmem_packet_scope(), hi_addr));
148             m->lo_addr = g_str_hash(address_to_str(wmem_packet_scope(), lo_addr));
149         break;
150     }
151
152     return m;
153 }
154
155 gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean keep_persistent_data) {
156     gcp_trx_t* t = NULL;
157     gcp_trx_msg_t* trxmsg;
158
159     if ( !m ) return NULL;
160
161     if (keep_persistent_data) {
162         if (m->committed) {
163
164             for ( trxmsg = m->trxs; trxmsg; trxmsg = trxmsg->next) {
165                 if (trxmsg->trx && trxmsg->trx->id == t_id) {
166                     return trxmsg->trx;
167                 }
168             }
169             DISSECTOR_ASSERT_NOT_REACHED();
170         } else {
171             wmem_tree_key_t key[4];
172
173             key[0].length = 1;
174             key[0].key = &(m->hi_addr);
175             key[1].length = 1;
176             key[1].key = &(m->lo_addr);
177             key[2].length = 1;
178             key[2].key = &(t_id);
179             key[3].length = 0;
180             key[3].key = NULL;
181
182             trxmsg = wmem_new(wmem_file_scope(), gcp_trx_msg_t);
183             t = (gcp_trx_t *)wmem_tree_lookup32_array(trxs,key);
184
185             if (!t) {
186                 t = wmem_new(wmem_file_scope(), gcp_trx_t);
187                 t->initial = m;
188                 t->id = t_id;
189                 t->type = type;
190                 t->pendings = 0;
191                 t->error = 0;
192                 t->cmds = NULL;
193
194                 wmem_tree_insert32_array(trxs,key,t);
195             }
196
197             /* XXX: request, reply and ack + point to frames where they are */
198             switch ( type ) {
199                 case GCP_TRX_PENDING:
200                     t->pendings++;
201                     break;
202                 default:
203                     break;
204             }
205
206         }
207     } else {
208         t = wmem_new(wmem_packet_scope(), gcp_trx_t);
209         trxmsg = wmem_new(wmem_packet_scope(), gcp_trx_msg_t);
210         t->initial = NULL;
211         t->id = t_id;
212         t->type = type;
213         t->pendings = 0;
214         t->error = 0;
215         t->cmds = NULL;
216     }
217
218     DISSECTOR_ASSERT(trxmsg);
219
220     trxmsg->trx = t;
221     trxmsg->next = NULL;
222     trxmsg->last = trxmsg;
223
224     if (m->trxs) {
225         m->trxs->last = m->trxs->last->next = trxmsg;
226     } else {
227         m->trxs = trxmsg;
228     }
229
230     return t;
231 }
232
233
234 gcp_ctx_t* gcp_ctx(gcp_msg_t* m, gcp_trx_t* t, guint32 c_id, gboolean persistent) {
235     gcp_ctx_t* context = NULL;
236     gcp_ctx_t** context_p = NULL;
237
238     if ( !m || !t ) return NULL;
239
240     if (persistent) {
241
242         wmem_tree_key_t ctx_key[4];
243         wmem_tree_key_t trx_key[4];
244
245         ctx_key[0].length = 1;
246         ctx_key[0].key = &(m->hi_addr);
247         ctx_key[1].length = 1;
248         ctx_key[1].key = &(m->lo_addr);
249         ctx_key[2].length = 1;
250         ctx_key[2].key = &(c_id);
251         ctx_key[3].length = 0;
252         ctx_key[3].key = NULL;
253
254         trx_key[0].length = 1;
255         trx_key[0].key = &(m->hi_addr);
256         trx_key[1].length = 1;
257         trx_key[1].key = &(m->lo_addr);
258         trx_key[2].length = 1;
259         trx_key[2].key = &(t->id);
260         trx_key[3].length = 0;
261         trx_key[3].key = NULL;
262
263         if (m->committed) {
264             if (( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
265                 return context;
266             } if ((context_p = (gcp_ctx_t **)wmem_tree_lookup32_array(ctxs,ctx_key))) {
267                 context = *context_p;
268
269                 do {
270                     if (context->initial->framenum <= m->framenum) {
271                         return context;
272                     }
273                 } while(( context = context->prev ));
274
275                 DISSECTOR_ASSERT(! "a context should exist");
276             }
277         } else {
278             if (c_id == CHOOSE_CONTEXT) {
279                 if (! ( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key))) {
280                     context = wmem_new(wmem_file_scope(), gcp_ctx_t);
281                     context->initial = m;
282                     context->cmds = NULL;
283                     context->id = c_id;
284                     context->terms.last = &(context->terms);
285                     context->terms.next = NULL;
286                     context->terms.term = NULL;
287
288                     wmem_tree_insert32_array(ctxs_by_trx,trx_key,context);
289                 }
290             } else {
291                 if (( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
292                     if (( context_p = (gcp_ctx_t **)wmem_tree_lookup32_array(ctxs,ctx_key) )) {
293                         if (context != *context_p) {
294                             if(context->id != CHOOSE_CONTEXT) {
295                                 context = wmem_new(wmem_file_scope(), gcp_ctx_t);
296                             }
297                             context->initial = m;
298                             context->id = c_id;
299                             context->cmds = NULL;
300                             context->terms.last = &(context->terms);
301                             context->terms.next = NULL;
302                             context->terms.term = NULL;
303
304                             context->prev = *context_p;
305                             *context_p = context;
306                         }
307                     } else {
308                         context_p = wmem_new(wmem_file_scope(), gcp_ctx_t*);
309                         *context_p = context;
310                         context->initial = m;
311                         context->id = c_id;
312                         wmem_tree_insert32_array(ctxs,ctx_key,context_p);
313                     }
314                 } else if (! ( context_p = (gcp_ctx_t**)wmem_tree_lookup32_array(ctxs,ctx_key) )) {
315                     context = wmem_new(wmem_file_scope(), gcp_ctx_t);
316                     context->initial = m;
317                     context->id = c_id;
318                     context->cmds = NULL;
319                     context->terms.last = &(context->terms);
320                     context->terms.next = NULL;
321                     context->terms.term = NULL;
322
323                     context_p = wmem_new(wmem_file_scope(), gcp_ctx_t*);
324                     *context_p = context;
325                     wmem_tree_insert32_array(ctxs,ctx_key,context_p);
326                 } else {
327                     context = *context_p;
328                 }
329             }
330         }
331     } else {
332         context = wmem_new(wmem_packet_scope(), gcp_ctx_t);
333         context->initial = m;
334         context->cmds = NULL;
335         context->id = c_id;
336         context->terms.last = &(context->terms);
337         context->terms.next = NULL;
338         context->terms.term = NULL;
339     }
340
341     return context;
342 }
343
344 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) {
345     gcp_cmd_t* cmd;
346     gcp_cmd_msg_t* cmdtrx;
347     gcp_cmd_msg_t* cmdctx;
348
349     if ( !m || !t || !c ) return NULL;
350
351     if (persistent) {
352         if (m->committed) {
353             DISSECTOR_ASSERT(t->cmds != NULL);
354
355             for (cmdctx = t->cmds; cmdctx; cmdctx = cmdctx->next) {
356                 cmd = cmdctx->cmd;
357                 if (cmd->msg == m && cmd->offset == offset) {
358                     return cmd;
359                 }
360             }
361
362             DISSECTOR_ASSERT(!"called for a command that does not exist!");
363
364             return NULL;
365         } else {
366             cmd = wmem_new(wmem_file_scope(), gcp_cmd_t);
367             cmdtrx = wmem_new(wmem_file_scope(), gcp_cmd_msg_t);
368             cmdctx = wmem_new(wmem_file_scope(), gcp_cmd_msg_t);
369         }
370     } else {
371         cmd = wmem_new(wmem_packet_scope(), gcp_cmd_t);
372         cmdtrx = wmem_new(wmem_packet_scope(), gcp_cmd_msg_t);
373         cmdctx = wmem_new(wmem_packet_scope(), gcp_cmd_msg_t);
374     }
375
376     cmd->type = type;
377     cmd->offset = offset;
378     cmd->terms.term = NULL;
379     cmd->terms.next = NULL;
380     cmd->terms.last = &(cmd->terms);
381     cmd->str = NULL;
382     cmd->msg = m;
383     if ((type != GCP_CMD_NONE) && (!persistent)){
384         cmd->str = val_to_str_const(type, gcp_cmd_type, "Unknown");
385     }
386     cmd->trx = t;
387     cmd->ctx = c;
388     cmd->error = 0;
389
390     cmdctx->cmd = cmdtrx->cmd = cmd;
391     cmdctx->next =  cmdtrx->next = NULL;
392     cmdctx->last = cmdtrx->last = NULL;
393
394     if (t->cmds) {
395         t->cmds->last->next = cmdtrx;
396         t->cmds->last = cmdtrx;
397     } else {
398         t->cmds = cmdtrx;
399         t->cmds->last = cmdtrx;
400     }
401
402     if (c->cmds) {
403         c->cmds->last->next = cmdctx;
404         c->cmds->last = cmdctx;
405     } else {
406         c->cmds = cmdctx;
407         c->cmds->last = cmdctx;
408     }
409
410     return cmd;
411 }
412
413
414 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) {
415     gcp_terms_t* ct;
416     gcp_terms_t* ct2;
417
418     static gcp_term_t all_terms = {"$",(const guint8*)"",1,GCP_TERM_TYPE_UNKNOWN,NULL,NULL,NULL};
419
420     if ( !c ) return NULL;
421
422     if ( wildcard == GCP_WILDCARD_CHOOSE) {
423         return &all_terms;
424     }
425
426     if (persistent) {
427         if ( c->msg->committed ) {
428             if (wildcard == GCP_WILDCARD_ALL) {
429                 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
430                     /* XXX not handling more wilcards in one msg */
431                     if ( ct->term->start == m ) {
432                         return ct->term;
433                     }
434                 }
435                 return NULL;
436             } else {
437                 for (ct = c->ctx->terms.next; ct; ct = ct->next) {
438                     if ( g_str_equal(ct->term->str,t->str) ) {
439                         return ct->term;
440                     }
441                 }
442                 return NULL;
443             }
444         } else {
445
446             for (ct = c->ctx->terms.next; ct; ct = ct->next) {
447                 if ( g_str_equal(ct->term->str,t->str) || ct->term->start == m) {
448                     break;
449                 }
450             }
451
452             if ( ! ct ) {
453
454                 if (wildcard == GCP_WILDCARD_ALL) {
455                     ct = wmem_new(wmem_file_scope(), gcp_terms_t);
456                     ct->next = NULL;
457                     ct->term = wmem_new0(wmem_file_scope(), gcp_term_t);
458
459                     ct->term->start = m;
460                     ct->term->str = "*";
461                     ct->term->buffer = NULL;
462                     ct->term->len = 0;
463
464                     c->terms.last = c->terms.last->next = ct;
465
466                     ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
467                     ct2->term = ct->term;
468
469                     c->ctx->terms.last->next = ct2;
470                     c->ctx->terms.last = ct2;
471
472                     return ct->term;
473                 } else {
474                     for (ct = c->ctx->terms.next; ct; ct = ct->next) {
475                         /* XXX not handling more wilcards in one msg */
476                         if ( ct->term->buffer == NULL && tr->cmds->cmd->msg == ct->term->start ) {
477                             ct->term->str = wmem_strdup(wmem_file_scope(), t->str);
478                             ct->term->buffer = (const guint8 *)wmem_memdup(wmem_file_scope(), t->buffer,t->len);
479                             ct->term->len = t->len;
480
481                             ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
482                             ct2->term = ct->term;
483
484                             c->terms.last = c->terms.last->next = ct2;
485
486                             return ct->term;
487                         }
488
489                         if  ( g_str_equal(ct->term->str,t->str) ) {
490                             ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
491                             ct2->term = ct->term;
492
493                             c->terms.last = c->terms.last->next = ct2;
494
495                             return ct->term;
496                         }
497                     }
498
499                     ct = wmem_new(wmem_file_scope(), gcp_terms_t);
500                     ct->next = NULL;
501                     ct->term = wmem_new0(wmem_file_scope(), gcp_term_t);
502
503                     ct->term->start = m;
504                     ct->term->str = wmem_strdup(wmem_file_scope(), t->str);
505                     ct->term->buffer = (const guint8 *)wmem_memdup(wmem_file_scope(), t->buffer,t->len);
506                     ct->term->len = t->len;
507
508                     ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
509                     ct2->term = ct->term;
510
511                     c->terms.last = c->terms.last->next = ct2;
512
513                     ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
514                     ct2->term = ct->term;
515
516                     c->ctx->terms.last = c->ctx->terms.last->next = ct2;
517
518                     return ct->term;
519                 }
520             } else {
521                 ct2 = wmem_new0(wmem_file_scope(), gcp_terms_t);
522                 ct2->term = ct->term;
523
524                 c->terms.last = c->terms.last->next = ct2;
525                 return ct->term;
526             }
527
528             DISSECTOR_ASSERT_NOT_REACHED();
529         }
530     } else {
531         ct = wmem_new(wmem_packet_scope(), gcp_terms_t);
532         ct->term = t;
533         ct->next = NULL;
534         c->terms.last = c->terms.last->next = ct;
535
536         return t;
537     }
538
539 }
540
541 const gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent) {
542     const gchar* s;
543     gcp_terms_t* term;
544
545     if ( !c ) return "-";
546
547     switch (c->type) {
548         case GCP_CMD_NONE:
549             return "-";
550             break;
551         case GCP_CMD_ADD_REQ:
552             s = "AddReq {";
553             break;
554         case GCP_CMD_MOVE_REQ:
555             s = "MoveReq {";
556             break;
557         case GCP_CMD_MOD_REQ:
558             s = "ModReq {";
559             break;
560         case GCP_CMD_SUB_REQ:
561             s = "SubReq {";
562             break;
563         case GCP_CMD_AUDITCAP_REQ:
564             s = "AuditCapReq {";
565             break;
566         case GCP_CMD_AUDITVAL_REQ:
567             s = "AuditValReq {";
568             break;
569         case GCP_CMD_NOTIFY_REQ:
570             s = "NotifyReq {";
571             break;
572         case GCP_CMD_SVCCHG_REQ:
573             s = "SvcChgReq {";
574             break;
575         case GCP_CMD_TOPOLOGY_REQ:
576             s = "TopologyReq {";
577             break;
578         case GCP_CMD_CTX_ATTR_AUDIT_REQ:
579             s = "CtxAttribAuditReq {";
580             break;
581         case GCP_CMD_ADD_REPLY:
582             s = "AddReply {";
583             break;
584         case GCP_CMD_MOVE_REPLY:
585             s = "MoveReply {";
586             break;
587         case GCP_CMD_MOD_REPLY:
588             s = "ModReply {";
589             break;
590         case GCP_CMD_SUB_REPLY:
591             s = "SubReply {";
592             break;
593         case GCP_CMD_AUDITCAP_REPLY:
594             s = "AuditCapReply {";
595             break;
596         case GCP_CMD_AUDITVAL_REPLY:
597             s = "AuditValReply {";
598             break;
599         case GCP_CMD_NOTIFY_REPLY:
600             s = "NotifyReply {";
601             break;
602         case GCP_CMD_SVCCHG_REPLY:
603             s = "SvcChgReply {";
604             break;
605         case GCP_CMD_TOPOLOGY_REPLY:
606             s = "TopologyReply {";
607             break;
608         case GCP_CMD_REPLY:
609             s = "ActionReply {";
610             break;
611         case GCP_CMD_OTHER_REQ:
612             s = "Request {";
613             break;
614         default:
615             s = "-";
616             break;
617     }
618
619     for (term = c->terms.next; term; term = term->next) {
620         s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,term->term->str);
621     }
622
623     if (c->error) {
624         s = wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s,c->error);
625     }
626
627     s = wmem_strdup_printf(wmem_packet_scope(), "%s }", s);
628
629     if (persistent) {
630         if (! c->str) c->str = wmem_strdup(wmem_file_scope(), s);
631     } else {
632         c->str = s;
633     }
634
635     return s;
636 }
637
638 static const gchar* gcp_trx_to_str(gcp_msg_t* m, gcp_trx_t* t, gboolean persistent) {
639     gchar* s;
640     gcp_cmd_msg_t* c;
641
642     if ( !m || !t ) return "-";
643
644     s = wmem_strdup_printf(wmem_packet_scope(), "T %x { ",t->id);
645
646     if (t->cmds) {
647         if (t->cmds->cmd->ctx) {
648             s = wmem_strdup_printf(wmem_packet_scope(), "%s C %x {",s,t->cmds->cmd->ctx->id);
649
650             for (c = t->cmds; c; c = c->next) {
651                 if (c->cmd->msg == m) {
652                     s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,gcp_cmd_to_str(c->cmd,persistent));
653                 }
654             }
655
656             s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,"}");
657         }
658     }
659
660     if (t->error) {
661         s = wmem_strdup_printf(wmem_packet_scope(), "%s Error=%i",s,t->error);
662     }
663
664     return wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,"}");
665 }
666
667 const gchar* gcp_msg_to_str(gcp_msg_t* m, gboolean persistent) {
668     gcp_trx_msg_t* t;
669     const gchar* s = "";
670
671     if ( !m ) return "-";
672
673     for (t = m->trxs; t; t = t->next) {
674         s = wmem_strdup_printf(wmem_packet_scope(), "%s %s",s,gcp_trx_to_str(m,t->trx, persistent));
675     }
676
677     return s;
678 }
679
680 typedef struct _gcp_ctxs_t {
681     struct _gcp_ctx_t* ctx;
682     struct _gcp_ctxs_t* next;
683 } gcp_ctxs_t;
684
685 /*static const gchar* trx_types[] = {"None","Req","Reply","Pending","Ack"};*/
686
687 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_trx_msg_t* t;
689     gcp_ctxs_t contexts = {NULL,NULL};
690     gcp_ctxs_t* ctx_node;
691     gcp_cmd_msg_t* c;
692
693
694     for (t = m->trxs; t; t = t->next) {
695         for (c = t->trx->cmds; c; c = c->next) {
696             gcp_ctx_t* ctx = c->cmd->ctx;
697
698             for (ctx_node = contexts.next; ctx_node; ctx_node = ctx_node->next) {
699                 if (ctx_node->ctx->id == ctx->id) {
700                     break;
701                 }
702             }
703
704             if (! ctx_node) {
705                 ctx_node = wmem_new(wmem_packet_scope(), gcp_ctxs_t);
706                 ctx_node->ctx = ctx;
707                 ctx_node->next = contexts.next;
708                 contexts.next = ctx_node;
709             }
710         }
711     }
712
713     for (ctx_node = contexts.next; ctx_node; ctx_node = ctx_node->next) {
714         gcp_ctx_t* ctx = ctx_node->ctx;
715         proto_item* ctx_item = proto_tree_add_uint(gcp_tree,ids->hf.ctx,gcp_tvb,0,0,ctx->id);
716         proto_tree* ctx_tree = proto_item_add_subtree(ctx_item,ids->ett.ctx);
717         gcp_terms_t *ctx_term;
718
719         PROTO_ITEM_SET_GENERATED(ctx_item);
720
721         if (ctx->cmds) {
722             proto_tree* history_tree = proto_tree_add_subtree(ctx_tree,gcp_tvb,0,0,ids->ett.ctx_cmds,NULL,"[ Command History ]");
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_tree* terms_tree = proto_tree_add_subtree(ctx_tree,gcp_tvb,0,0,ids->ett.ctx_terms,NULL,"[ Terminations Used ]");
736
737             for (; ctx_term; ctx_term = ctx_term->next ) {
738                 if ( ctx_term->term && ctx_term->term->str) {
739                     proto_item* pi = proto_tree_add_string(terms_tree,ids->hf.ctx_term,gcp_tvb,0,0,ctx_term->term->str);
740                     proto_tree* term_tree = proto_item_add_subtree(pi,ids->ett.ctx_term);
741
742                     PROTO_ITEM_SET_GENERATED(pi);
743
744                     if (ctx_term->term->type) {
745                         pi = proto_tree_add_uint(term_tree,ids->hf.ctx_term_type,gcp_tvb,0,0,ctx_term->term->type);
746                         PROTO_ITEM_SET_GENERATED(pi);
747                     }
748
749                     if (ctx_term->term->bir) {
750                         pi = proto_tree_add_string(term_tree,ids->hf.ctx_term_bir,gcp_tvb,0,0,ctx_term->term->bir);
751                         PROTO_ITEM_SET_GENERATED(pi);
752                     }
753
754                     if (ctx_term->term->nsap) {
755                         pi = proto_tree_add_string(term_tree,ids->hf.ctx_term_nsap,gcp_tvb,0,0,ctx_term->term->nsap);
756                         PROTO_ITEM_SET_GENERATED(pi);
757                     }
758
759                     if (ctx_term->term->bir && ctx_term->term->nsap) {
760                         gchar* tmp_key = wmem_strdup_printf(wmem_packet_scope(), "%s:%s",ctx_term->term->nsap,ctx_term->term->bir);
761                         gchar* key = g_ascii_strdown(tmp_key, -1);
762                         alcap_tree_from_bearer_key(term_tree, gcp_tvb, pinfo, key);
763                         g_free(key);
764                     }
765                 }
766             }
767         }
768     }
769 }
770
771 /*
772  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
773  *
774  * Local variables:
775  * c-basic-offset: 4
776  * tab-width: 8
777  * indent-tabs-mode: nil
778  * End:
779  *
780  * vi: set shiftwidth=4 tabstop=8 expandtab:
781  * :indentSize=4:tabSize=8:noTabs=true:
782  */