* Copyright 2004, Iskratel, Ltd, Kranj
* By Miha Jemec <m.jemec@iskratel.si>
*
- * H323, RTP and Graph Support
+ * H323, RTP, MGCP and Graph Support
* By Alejandro Vaquero, alejandro.vaquero@verso.com
* Copyright 2005, Verso Technologies Inc.
*
# include "config.h"
#endif
+#include <string.h>
+
#include "graph_analysis.h"
#include "voip_calls.h"
#include "voip_calls_dlg.h"
-#include "rtp_stream.h"
#include "globals.h"
#include <epan/dissectors/packet-h245.h>
#include <epan/dissectors/packet-q931.h>
#include <epan/dissectors/packet-sdp.h>
+#include <plugins/mgcp/packet-mgcp.h>
#include <epan/dissectors/packet-rtp.h>
#include "rtp_pt.h"
#include "alert_box.h"
#include "simple_dialog.h"
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#include <string.h>
-
-
-char *voip_call_state_name[6]={
+char *voip_call_state_name[7]={
"CALL SETUP",
+ "RINGING",
"IN CALL",
"CANCELLED",
"COMPLETED",
};
/* defines whether we can consider the call active */
-char *voip_protocol_name[3]={
+char *voip_protocol_name[4]={
"SIP",
"ISUP",
- "H323"
+ "H323",
+ "MGCP"
};
/****************************************************************************/
/* the one and only global voip_calls_tapinfo_t structure */
static voip_calls_tapinfo_t the_tapinfo_struct =
- {0, NULL, 0, NULL, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0};
+ {0, NULL, 0, NULL, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0};
/* the one and only global voip_rtp_tapinfo_t structure */
static voip_rtp_tapinfo_t the_tapinfo_rtp_struct =
voip_calls_info_t *strinfo;
sip_calls_info_t *tmp_sipinfo;
h323_calls_info_t *tmp_h323info;
+ h245_address_t *h245_add;
graph_analysis_item_t *graph_item;
strinfo = list->data;
g_free(strinfo->from_identity);
g_free(strinfo->to_identity);
+ g_free((void *)(strinfo->initial_speaker.data));
if (strinfo->protocol == VOIP_SIP){
tmp_sipinfo = strinfo->prot_info;
g_free(tmp_sipinfo->call_identifier);
list2 = g_list_first(tmp_h323info->h245_list);
while (list2)
{
+ h245_add=list2->data;
+ g_free((void *)h245_add->h245_address.data);
g_free(list2->data);
list2 = g_list_next(list2);
}
gai = g_malloc(sizeof(graph_analysis_item_t));
gai->frame_num = pinfo->fd->num;
gai->time= (double)pinfo->fd->rel_secs + (double) pinfo->fd->rel_usecs/1000000;
- g_memmove(&gai->ip_src, pinfo->src.data, 4);
- g_memmove(&gai->ip_dst, pinfo->dst.data, 4);
+ COPY_ADDRESS(&(gai->src_addr),&(pinfo->src));
+ COPY_ADDRESS(&(gai->dst_addr),&(pinfo->dst));
gai->port_src=pinfo->srcport;
gai->port_dst=pinfo->destport;
if (frame_label != NULL)
}
+/****************************************************************************/
+/* Change all the graph items with call_num to new_call_num */
+guint change_call_num_graph(voip_calls_tapinfo_t *tapinfo _U_, guint16 call_num, guint16 new_call_num)
+{
+ graph_analysis_item_t *gai;
+ GList* list;
+ guint items_changed;
+
+ items_changed = 0;
+ list = g_list_first(tapinfo->graph_analysis->list);
+ while (list)
+ {
+ gai = list->data;
+ if (gai->conv_num == call_num){
+ gai->conv_num = new_call_num;
+ items_changed++;
+ }
+ list = g_list_next (list);
+ }
+ return items_changed;
+}
+
/****************************************************************************/
/* ***************************TAP for RTP **********************************/
/****************************************************************************/
while (list)
{
tmp_listinfo=list->data;
- if ( (tmp_listinfo->setup_frame_number == pi->info_setup_frame_num) && (tmp_listinfo->ssrc == pi->info_sync_src) ){
+ if ( (tmp_listinfo->setup_frame_number == pi->info_setup_frame_num)
+ && (tmp_listinfo->ssrc == pi->info_sync_src) && (tmp_listinfo->end_stream == FALSE)){
+ /* if the payload type has changed, we mark the stream as finished to create a new one
+ this is to show multiple payload changes in the Graph for example for DTMF RFC2833 */
+ if ( tmp_listinfo->pt != pi->info_payload_type )
+ tmp_listinfo->end_stream = TRUE;
+ else {
strinfo = (voip_rtp_stream_info_t*)(list->data);
break;
+ }
}
list = g_list_next (list);
}
COPY_ADDRESS(&(strinfo->dest_addr), &(pinfo->dst));
strinfo->dest_port = pinfo->destport;
strinfo->ssrc = pi->info_sync_src;
+ strinfo->end_stream = FALSE;
strinfo->pt = pi->info_payload_type;
strinfo->npackets = 0;
strinfo->first_frame_num = pinfo->fd->num;
new_gai = g_malloc(sizeof(graph_analysis_item_t));
new_gai->frame_num = rtp_listinfo->first_frame_num;
new_gai->time = (double)rtp_listinfo->start_rel_sec + (double)rtp_listinfo->start_rel_usec/1000000;
- g_memmove(&new_gai->ip_src, rtp_listinfo->src_addr.data, 4);
- g_memmove(&new_gai->ip_dst, rtp_listinfo->dest_addr.data, 4);
+ COPY_ADDRESS(&(new_gai->src_addr),&(rtp_listinfo->src_addr));
+ COPY_ADDRESS(&(new_gai->dst_addr),&(rtp_listinfo->dest_addr));
new_gai->port_src = rtp_listinfo->src_port;
new_gai->port_dst = rtp_listinfo->dest_port;
duration = (rtp_listinfo->stop_rel_sec*1000000 + rtp_listinfo->stop_rel_usec) - (rtp_listinfo->start_rel_sec*1000000 + rtp_listinfo->start_rel_usec);
voip_calls_info_t *tmp_listinfo;
voip_calls_info_t *strinfo = NULL;
- sip_calls_info_t *tmp_sipinfo;
+ sip_calls_info_t *tmp_sipinfo = NULL;
GList* list;
- guint32 tmp_src, tmp_dst;
+ address tmp_src, tmp_dst;
gchar *frame_label = NULL;
gchar *comment = NULL;
strinfo->call_state = VOIP_CALL_SETUP;
strinfo->from_identity=g_strdup(pi->tap_from_addr);
strinfo->to_identity=g_strdup(pi->tap_to_addr);
- g_memmove(&(strinfo->initial_speaker), pinfo->src.data, 4);
+ COPY_ADDRESS(&(strinfo->initial_speaker),&(pinfo->src));
strinfo->first_frame_num=pinfo->fd->num;
strinfo->selected=FALSE;
strinfo->start_sec=pinfo->fd->rel_secs;
/* let's analyze the call state */
- g_memmove(&(tmp_src), pinfo->src.data, 4);
- g_memmove(&(tmp_dst), pinfo->dst.data, 4);
+ COPY_ADDRESS(&(tmp_src), &(pinfo->src));
+ COPY_ADDRESS(&(tmp_dst), &(pinfo->dst));
if (pi->request_method == NULL){
frame_label = g_strdup_printf("%d %s", pi->response_code, pi->reason_phrase );
comment = g_strdup_printf("SIP Status");
- if ((pi->tap_cseq_number == tmp_sipinfo->invite_cseq)&&(tmp_dst==strinfo->initial_speaker)){
+ if ((tmp_sipinfo && pi->tap_cseq_number == tmp_sipinfo->invite_cseq)&&(ADDRESSES_EQUAL(&tmp_dst,&(strinfo->initial_speaker)))){
if ((pi->response_code > 199) && (pi->response_code<300) && (tmp_sipinfo->sip_state == SIP_INVITE_SENT)){
tmp_sipinfo->sip_state = SIP_200_REC;
}
else{
frame_label = g_strdup(pi->request_method);
- if ((strcmp(pi->request_method,"INVITE")==0)&&(tmp_src == strinfo->initial_speaker)){
+ if ((strcmp(pi->request_method,"INVITE")==0)&&(ADDRESSES_EQUAL(&tmp_src,&(strinfo->initial_speaker)))){
tmp_sipinfo->invite_cseq = pi->tap_cseq_number;
+ strinfo->call_state = VOIP_CALL_SETUP;
comment = g_strdup_printf("SIP From: %s To:%s", strinfo->from_identity, strinfo->to_identity);
}
else if ((strcmp(pi->request_method,"ACK")==0)&&(pi->tap_cseq_number == tmp_sipinfo->invite_cseq)
- &&(tmp_src == strinfo->initial_speaker)&&(tmp_sipinfo->sip_state==SIP_200_REC)){
+ &&(ADDRESSES_EQUAL(&tmp_src,&(strinfo->initial_speaker)))&&(tmp_sipinfo->sip_state==SIP_200_REC)
+ &&(strinfo->call_state == VOIP_CALL_SETUP)){
strinfo->call_state = VOIP_IN_CALL;
comment = g_strdup_printf("SIP Request");
}
comment = g_strdup_printf("SIP Request");
}
else if ((strcmp(pi->request_method,"CANCEL")==0)&&(pi->tap_cseq_number == tmp_sipinfo->invite_cseq)
- &&(tmp_src == strinfo->initial_speaker)&&(strinfo->call_state==VOIP_CALL_SETUP)){
+ &&(ADDRESSES_EQUAL(&tmp_src,&(strinfo->initial_speaker)))&&(strinfo->call_state==VOIP_CALL_SETUP)){
strinfo->call_state = VOIP_CANCELLED;
tmp_sipinfo->sip_state = SIP_CANCEL_SENT;
comment = g_strdup_printf("SIP Request");
add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num);
g_free(comment);
g_free(frame_label);
+ g_free((void *)tmp_src.data);
+ g_free((void *)tmp_dst.data);
}
return 1; /* refresh output */
}
static guint16 isup_cic;
static guint8 isup_message_type;
static guint8 isup_cause_value;
+static guint32 isup_frame_num;
/****************************************************************************/
/* whenever a isup_ packet is seen by the tap listener */
static int
isup_calls_packet(void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *isup_info _U_)
{
- voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct;
+ /*voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct; unused */
const isup_tap_rec_t *pi = isup_info;
if (pi->calling_number!=NULL){
isup_cause_value = pi->cause_value;
isup_cic = pinfo->circuit_id;
+ isup_frame_num = pinfo->fd->num;
+
return 0;
}
voip_calls_info_t *strinfo = NULL;
isup_calls_info_t *tmp_isupinfo;
gboolean found = FALSE;
- gboolean forward;
+ gboolean forward = FALSE;
gboolean right_pair = TRUE;
GList* list;
gchar *frame_label = NULL;
const mtp3_tap_rec_t *pi = mtp3_info;
+ /* check if the upper layer is ISUP matching the frame number */
+ if (isup_frame_num != pinfo->fd->num) return 0;
+
/* check wether we already have a call with these parameters in the list */
list = g_list_first(tapinfo->strinfo_list);
while (list)
tmp_listinfo=list->data;
if ((tmp_listinfo->protocol == VOIP_ISUP)&&(tmp_listinfo->call_active_state==VOIP_ACTIVE)){
tmp_isupinfo = tmp_listinfo->prot_info;
- if ((tmp_isupinfo->cic == isup_cic)&&(tmp_isupinfo->ni == pi->addr_opc.ni)){
+ if ((tmp_isupinfo->cic == isup_cic)&&(tmp_isupinfo->ni == pi->addr_opc.ni)) {
if ((tmp_isupinfo->opc == pi->addr_opc.pc)&&(tmp_isupinfo->dpc == pi->addr_dpc.pc)){
forward = TRUE;
}
forward = FALSE;
}
else{
+ /* XXX: what about forward is it FALSE as declared or should it be true */
right_pair = FALSE;
}
if (right_pair){
strinfo = g_malloc(sizeof(voip_calls_info_t));
strinfo->call_active_state = VOIP_ACTIVE;
strinfo->call_state = VOIP_UNKNOWN;
- g_memmove(&(strinfo->initial_speaker), pinfo->src.data, 4);
+ COPY_ADDRESS(&(strinfo->initial_speaker),&(pinfo->src));
strinfo->selected=FALSE;
strinfo->first_frame_num=pinfo->fd->num;
strinfo->start_sec=pinfo->fd->rel_secs;
static int
q931_calls_packet(void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *q931_info _U_)
{
- voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct;
+ /*voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct; */
const q931_packet_info *pi = q931_info;
/* free previously allocated q931_calling/ed_number */
static const guint8 guid_allzero[GUID_LEN] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* defines specific H323 data */
-void add_h245_Address(h323_calls_info_t *h323info, guint32 h245_address, guint16 h245_port)
-{
- h245_address_t *h245_add = NULL;
- h245_add = g_malloc(sizeof(h245_address_t));
- h245_add->h245_address = h245_address;
- h245_add->h245_port = h245_port;
-
- h323info->h245_list = g_list_append(h323info->h245_list, h245_add);
+void add_h245_Address(h323_calls_info_t *h323info, h245_address_t *h245_address)
+{
+ h323info->h245_list = g_list_append(h323info->h245_list, h245_address);
}
/****************************************************************************/
voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct;
voip_calls_info_t *tmp_listinfo;
voip_calls_info_t *strinfo = NULL;
- h323_calls_info_t *tmp_h323info;
+ h323_calls_info_t *tmp_h323info = NULL;
+ h323_calls_info_t *tmp2_h323info;
gchar *frame_label;
gchar *comment;
- GList* list;
- guint32 tmp_src, tmp_dst;
-
+ GList *list, *list2;
+ address tmp_src, tmp_dst;
+ h245_address_t *h245_add = NULL;
+ guint foo;
+
const h225_packet_info *pi = H225info;
-
- /* if not guid and RAS return because did not belong to a call */
- if ((memcmp(pi->guid, guid_allzero, GUID_LEN) == 0) && (pi->msg_type == H225_RAS))
+
+ /* if not guid and RAS and not LRQ, LCF or LRJ return because did not belong to a call */
+ if ((memcmp(pi->guid, guid_allzero, GUID_LEN) == 0) && (pi->msg_type == H225_RAS) && ((pi->msg_tag < 18) || (pi->msg_tag > 20)))
return 0;
-
+
if ( (memcmp(pi->guid, guid_allzero, GUID_LEN) == 0) && (q931_frame_num == pinfo->fd->num) ){
/* check wether we already have a call with this Q931 CRV */
list = g_list_first(tapinfo->strinfo_list);
list = g_list_next (list);
}
if (strinfo==NULL) return 0;
+ } else if ( (pi->msg_type == H225_RAS) && ((pi->msg_tag == 19) || (pi->msg_tag == 20))) { /* RAS LCF or LRJ*/
+ /* if the LCF/LRJ doesn't match to a LRQ, just return */
+ if (!pi->request_available) return 0;
+
+ /* check wether we already have a call with this request SeqNum */
+ list = g_list_first(tapinfo->strinfo_list);
+ while (list)
+ {
+ tmp_listinfo=list->data;
+ if (tmp_listinfo->protocol == VOIP_H323){
+ tmp_h323info = tmp_listinfo->prot_info;
+ if (tmp_h323info->requestSeqNum == pi->requestSeqNum) {
+ strinfo = (voip_calls_info_t*)(list->data);
+ break;
+ }
+ }
+ list = g_list_next (list);
+ }
} else {
/* check wether we already have a call with this guid in the list */
list = g_list_first(tapinfo->strinfo_list);
tmp_listinfo=list->data;
if (tmp_listinfo->protocol == VOIP_H323){
tmp_h323info = tmp_listinfo->prot_info;
- if (memcmp(tmp_h323info->guid, pi->guid,GUID_LEN)==0){
+ if ( (memcmp(tmp_h323info->guid, guid_allzero, GUID_LEN) != 0) && (memcmp(tmp_h323info->guid, pi->guid,GUID_LEN)==0) ){
strinfo = (voip_calls_info_t*)(list->data);
break;
}
list = g_list_next (list);
}
}
-
+
/* not in the list? then create a new entry */
if ((strinfo==NULL)){
strinfo = g_malloc(sizeof(voip_calls_info_t));
strinfo->call_state = VOIP_UNKNOWN;
strinfo->from_identity=g_strdup("");
strinfo->to_identity=g_strdup("");
-
- g_memmove(&(strinfo->initial_speaker), pinfo->src.data,4);
+ COPY_ADDRESS(&(strinfo->initial_speaker),&(pinfo->src));
strinfo->selected=FALSE;
strinfo->first_frame_num=pinfo->fd->num;
strinfo->start_sec=pinfo->fd->rel_secs;
strinfo->prot_info=g_malloc(sizeof(h323_calls_info_t));
tmp_h323info = strinfo->prot_info;
tmp_h323info->guid = (guint8 *) g_memdup(pi->guid,GUID_LEN);
- tmp_h323info->h225SetupAddr = 0;
+ tmp_h323info->h225SetupAddr.type = AT_NONE;
+ tmp_h323info->h225SetupAddr.len = 0;
tmp_h323info->h245_list = NULL;
tmp_h323info->is_faststart_Setup = FALSE;
tmp_h323info->is_faststart_Proc = FALSE;
tmp_h323info->is_h245 = FALSE;
tmp_h323info->q931_crv = -1;
tmp_h323info->q931_crv2 = -1;
+ tmp_h323info->requestSeqNum = 0;
strinfo->call_num = tapinfo->ncalls++;
strinfo->npackets = 0;
-
+
tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo);
}
/* let's analyze the call state */
- g_memmove(&(tmp_src), pinfo->src.data, 4);
- g_memmove(&(tmp_dst), pinfo->dst.data, 4);
+ COPY_ADDRESS(&(tmp_src),&(pinfo->src));
+ COPY_ADDRESS(&(tmp_dst),&(pinfo->dst));
strinfo->stop_sec=pinfo->fd->rel_secs;
strinfo->stop_usec=pinfo->fd->rel_usecs;
/* increment the packets counter of all calls */
++(tapinfo->npackets);
+
+ /* XXX: it is supposed to be initialized isn't it? */
+ g_assert(tmp_h323info != NULL);
+
/* change the status */
if (pi->msg_type == H225_CS){
if (tmp_h323info->q931_crv == -1) {
tmp_h323info->q931_crv2 = q931_crv;
}
+ /* this is still IPv4 only, because the dissector is */
if (pi->is_h245 == TRUE){
- add_h245_Address(tmp_h323info, pi->h245_address, pi->h245_port);
+ h245_add = g_malloc(sizeof (h245_address_t));
+ h245_add->h245_address.type=AT_IPv4;
+ h245_add->h245_address.len=4;
+ h245_add->h245_address.data = g_malloc(sizeof(pi->h245_address));
+ g_memmove((void *)(h245_add->h245_address.data), &(pi->h245_address), 4);
+ h245_add->h245_port = pi->h245_port;
+ add_h245_Address(tmp_h323info, h245_add);
}
if (pi->cs_type != H225_RELEASE_COMPLET) tmp_h323info->is_h245Tunneling = pi->is_h245Tunneling;
switch(pi->cs_type){
case H225_SETUP:
tmp_h323info->is_faststart_Setup = pi->is_faststart;
-
/* set te calling and called number from the Q931 packet */
if (q931_frame_num == pinfo->fd->num){
if (q931_calling_number != NULL){
strinfo->to_identity=g_strdup(q931_called_number);
}
}
- if (tmp_h323info->h225SetupAddr == 0) g_memmove(&(tmp_h323info->h225SetupAddr), pinfo->src.data,4);
- strinfo->call_state=VOIP_CALL_SETUP;
+ /* check if there is an LRQ/LCF that match this Setup */
+ /* TODO: we are just checking the DialedNumer in LRQ/LCF agains the Setup
+ we should also check if the h225 signaling IP and port match the destination
+ Setup ip and port */
+ list = g_list_first(tapinfo->strinfo_list);
+ foo= g_list_length(list);
+ while (list)
+ {
+ tmp_listinfo=list->data;
+ if (tmp_listinfo->protocol == VOIP_H323){
+ tmp2_h323info = tmp_listinfo->prot_info;
+
+ /* check if there called number match a LRQ/LCF */
+ if ( (strcmp(strinfo->to_identity, tmp_listinfo->to_identity)==0)
+ && (memcmp(tmp2_h323info->guid, guid_allzero, GUID_LEN) == 0) ){
+ /* change the call graph to the LRQ/LCF to belong to this call */
+ strinfo->npackets += change_call_num_graph(tapinfo, tmp_listinfo->call_num, strinfo->call_num);
+
+ /* remove this LRQ/LCF call entry because we have found the Setup that match them */
+ g_free(tmp_listinfo->from_identity);
+ g_free(tmp_listinfo->to_identity);
+ g_free(tmp2_h323info->guid);
+
+ list2 = g_list_first(tmp2_h323info->h245_list);
+ while (list2)
+ {
+ h245_add=list2->data;
+ g_free((void *)h245_add->h245_address.data);
+ g_free(list2->data);
+ list2 = g_list_next(list2);
+ }
+ g_list_free(tmp_h323info->h245_list);
+ tmp_h323info->h245_list = NULL;
+ g_free(tmp_listinfo->prot_info);
+ tapinfo->strinfo_list = g_list_remove(tapinfo->strinfo_list, tmp_listinfo);
+ break;
+ }
+ }
+ list = g_list_next (list);
+ }
+ foo = g_list_length(list);
+ /* Set the Setup address if it was not set */
+ if (tmp_h323info->h225SetupAddr.type == AT_NONE)
+ COPY_ADDRESS(&(tmp_h323info->h225SetupAddr), &(pinfo->src));
+ strinfo->call_state=VOIP_CALL_SETUP;
comment = g_strdup_printf("H225 From: %s To:%s TunnH245:%s FS:%s", strinfo->from_identity, strinfo->to_identity, (tmp_h323info->is_h245Tunneling==TRUE?"on":"off"),
- (pi->is_faststart==TRUE?"on":"off"));
+ (pi->is_faststart==TRUE?"on":"off"));
break;
case H225_CONNECT:
strinfo->call_state=VOIP_IN_CALL;
if (pi->is_faststart == TRUE) tmp_h323info->is_faststart_Proc = TRUE;
- comment = g_strdup_printf("H225 TunnH245:%s FS:%s", (tmp_h323info->is_h245Tunneling==TRUE?"on":"off"),
- (pi->is_faststart==TRUE?"on":"off"));
+ comment = g_strdup_printf("H225 TunnH245:%s FS:%s", (tmp_h323info->is_h245Tunneling==TRUE?"on":"off"),
+ (pi->is_faststart==TRUE?"on":"off"));
break;
case H225_RELEASE_COMPLET:
- g_memmove(&(tmp_src), pinfo->src.data, 4);
+ COPY_ADDRESS(&tmp_src,&(pinfo->src));
if (strinfo->call_state==VOIP_CALL_SETUP){
- if (tmp_h323info->h225SetupAddr == tmp_src){ /* forward direction */
+ if (ADDRESSES_EQUAL(&(tmp_h323info->h225SetupAddr),&tmp_src)){ /* forward direction */
strinfo->call_state=VOIP_CANCELLED;
}
else{ /* reverse */
strinfo->call_state=VOIP_REJECTED;
tapinfo->rejected_calls++;
}
- }
- else if (strinfo->call_state == VOIP_IN_CALL){
- strinfo->call_state = VOIP_COMPLETED;
- tapinfo->completed_calls++;
+ } else {
+ strinfo->call_state=VOIP_COMPLETED;
+ tapinfo->completed_calls++;
}
/* get the Q931 Release cause code */
if (q931_frame_num == pinfo->fd->num &&
- q931_cause_value != 0xFF){
+ q931_cause_value != 0xFF){
comment = g_strdup_printf("H225 Q931 Rel Cause (%i):%s", q931_cause_value, val_to_str(q931_cause_value, q931_cause_code_vals, "<unknown>"));
} else { /* Cause not set */
comment = g_strdup("H225 No Q931 Rel Cause");
case H225_CALL_PROCEDING:
if (pi->is_faststart == TRUE) tmp_h323info->is_faststart_Proc = TRUE;
comment = g_strdup_printf("H225 TunnH245:%s FS:%s", (tmp_h323info->is_h245Tunneling==TRUE?"on":"off"),
- (pi->is_faststart==TRUE?"on":"off"));
+ (pi->is_faststart==TRUE?"on":"off"));
break;
default:
comment = g_strdup_printf("H225 TunnH245:%s FS:%s", (tmp_h323info->is_h245Tunneling==TRUE?"on":"off"),
- (pi->is_faststart==TRUE?"on":"off"));
-
- }
- } else if (pi->msg_type == H225_RAS){
- frame_label = g_strdup_printf("%s", val_to_str(pi->msg_tag, RasMessage_vals, "<unknown>"));
- comment = g_strdup("H225 RAS");
- } else {
- frame_label = g_strdup("H225: Unknown");
- comment = g_strdup("");
+ (pi->is_faststart==TRUE?"on":"off"));
+
+ } /* switch pi->cs_type*/
+ } /* if pi->msg_type == H225_CS */
+ else if (pi->msg_type == H225_RAS){
+ switch(pi->msg_tag){
+ case 18: /* LRQ */
+ if (!pi->is_duplicate){
+ g_free(strinfo->to_identity);
+ strinfo->to_identity=g_strdup(pi->dialedDigits);
+ tmp_h323info->requestSeqNum = pi->requestSeqNum;
+ }
+ case 19: /* LCF */
+ if (strlen(pi->dialedDigits))
+ comment = g_strdup_printf("H225 RAS dialedDigits: %s", pi->dialedDigits);
+ else
+ comment = g_strdup("H225 RAS");
+ break;
+ default:
+ comment = g_strdup("H225 RAS");
}
+ frame_label = g_strdup_printf("%s", val_to_str(pi->msg_tag, RasMessage_vals, "<unknown>"));
+ } else {
+ frame_label = g_strdup("H225: Unknown");
+ comment = g_strdup("");
+ }
- /* add to graph analysis */
- if (!append_to_frame_graph(tapinfo, pinfo->fd->num, pi->frame_label, comment)) /* if the frame number exists in graph, append to it*/
- add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num); /* if not exist, add to the graph */
+ /* add to graph analysis */
- g_free(frame_label);
- g_free(comment);
+ /* if the frame number exists in graph, append to it*/
+ if (!append_to_frame_graph(tapinfo, pinfo->fd->num, pi->frame_label, comment)) {
+ /* if not exist, add to the graph */
+ add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num);
+ g_free((void *)tmp_src.data);
+ g_free((void *)tmp_dst.data);
}
+ g_free(frame_label);
+ g_free(comment);
+
+ } /* if strinfo!=NULL */
+
return 1; /* refresh output */
}
gchar *comment;
GList* list;
GList* list2;
- guint32 tmp_src, tmp_dst;
+ address tmp_src, tmp_dst;
h245_address_t *h245_add = NULL;
const h245_packet_info *pi = H245info;
if (tmp_listinfo->protocol == VOIP_H323){
tmp_h323info = tmp_listinfo->prot_info;
- g_memmove(&(tmp_src), pinfo->src.data, 4);
- g_memmove(&(tmp_dst), pinfo->dst.data, 4);
+ COPY_ADDRESS(&(tmp_src), &(pinfo->src));
+ COPY_ADDRESS(&(tmp_dst), &(pinfo->dst));
list2 = g_list_first(tmp_h323info->h245_list);
while (list2)
{
h245_add=list2->data;
- if ( ((h245_add->h245_address == tmp_src) && (h245_add->h245_port == pinfo->srcport))
- || ((h245_add->h245_address == tmp_dst) && (h245_add->h245_port == pinfo->destport)) ){
+ if ( (ADDRESSES_EQUAL(&(h245_add->h245_address),&tmp_src) && (h245_add->h245_port == pinfo->srcport))
+ || (ADDRESSES_EQUAL(&(h245_add->h245_address),&tmp_dst) && (h245_add->h245_port == pinfo->destport)) ){
strinfo = (voip_calls_info_t*)(list->data);
++(strinfo->npackets);
list2 = g_list_next(list2);
}
if (strinfo!=NULL) break;
+ g_free((void *)tmp_src.data);
+ g_free((void *)tmp_dst.data);
}
list = g_list_next(list);
}
have_H245dg_tap_listener=FALSE;
}
+static gchar *sdp_summary = NULL;
+static guint32 sdp_frame_num = 0;
/****************************************************************************/
/****************************TAP for SDP PROTOCOL ***************************/
{
voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct;
const sdp_packet_info *pi = SDPinfo;
- char summary_str[50];
-
+
+ /* There are protocols like MGCP where the SDP is called before the tap for the
+ MGCP packet, in those cases we assign the SPD summary to global lastSDPsummary
+ to use it later
+ */
+ g_free(sdp_summary);
+ sdp_frame_num = pinfo->fd->num;
/* Append to graph the SDP summary if the packet exists */
- g_snprintf(summary_str, 50, "SDP (%s)", pi->summary_str);
- append_to_frame_graph(tapinfo, pinfo->fd->num, summary_str, NULL);
+ sdp_summary = g_strdup_printf("SDP (%s)", pi->summary_str);
+ append_to_frame_graph(tapinfo, pinfo->fd->num, sdp_summary, NULL);
return 1; /* refresh output */
}
+/****************************************************************************/
+/* ***************************TAP for MGCP **********************************/
+/****************************************************************************/
+
+/*
+ This function will look for a signal/event in the SignalReq/ObsEvent string
+ and return true if it is found
+*/
+gboolean isSignal(gchar *signal, gchar *signalStr)
+{
+ gint i;
+ gchar **resultArray;
+
+ /* if there is no signalStr, just return false */
+ if (signalStr == NULL) return FALSE;
+
+ /* if are both "blank" return true */
+ if ( (*signal == '\0') && (*signalStr == '\0') ) return TRUE;
+
+ /* look for signal in signalSre */
+ resultArray = g_strsplit(signalStr, ",", 10);
+
+ for (i = 0; resultArray[i]; i++) {
+ g_strstrip(resultArray[i]);
+ if (strcmp(resultArray[i], signal) == 0) return TRUE;
+ }
+
+ g_strfreev(resultArray);
+
+ return FALSE;
+}
+
+/*
+ This function will get the Caller ID info and replace the current string
+ This is how it looks the caller Id: rg, ci(02/16/08/29, "3035550002","Ale Sipura 2")
+*/
+void mgcpCallerID(gchar *signalStr, gchar **callerId)
+{
+ gchar **arrayStr;
+
+ /* if there is no signalStr, just return false */
+ if (signalStr == NULL) return;
+
+ arrayStr = g_strsplit(signalStr, "\"", 10);
+
+ if (arrayStr[0] == NULL) return;
+
+ /* look for the ci signal */
+ if (strstr(arrayStr[0], "ci(") && (arrayStr[1] != NULL) ) {
+ /* free the previous "From" field of the call, and assign the new */
+ g_free(*callerId);
+ *callerId = g_strdup(arrayStr[1]);
+ }
+ g_strfreev(arrayStr);
+
+ return;
+}
+
+
+/*
+ This function will get the Dialed Digits and replace the current string
+ This is how it looks the dialed digits 5,5,5,0,0,0,2,#,*
+*/
+void mgcpDialedDigits(gchar *signalStr, gchar **dialedDigits)
+{
+ gchar *tmpStr;
+ gchar resultStr[50];
+ gint i,j;
+
+ /* if there is no signalStr, just return false */
+ if (signalStr == NULL) return;
+
+ tmpStr = g_strdup(signalStr);
+
+ for ( i = 0 ; tmpStr[i] ; i++) {
+ switch (tmpStr[i]) {
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ case '#' : case '*' :
+ break;
+ default:
+ tmpStr[i] = '?';
+ break;
+ }
+ }
+
+ for (i = 0, j = 0; tmpStr[i] && i<50; i++) {
+ if (tmpStr[i] != '?')
+ resultStr[j++] = tmpStr[i];
+ }
+ resultStr[j] = '\0';
+
+ if (*resultStr == '\0') return;
+
+ g_free(*dialedDigits);
+ *dialedDigits = g_strdup(resultStr);
+ g_free(tmpStr);
+
+ return;
+}
+
+
+
+/****************************************************************************/
+/* whenever a MGCP packet is seen by the tap listener */
+static int
+MGCPcalls_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *MGCPinfo)
+{
+ voip_calls_tapinfo_t *tapinfo = &the_tapinfo_struct;
+
+ voip_calls_info_t *tmp_listinfo;
+ voip_calls_info_t *strinfo = NULL;
+ mgcp_calls_info_t *tmp_mgcpinfo = NULL;
+ GList* list;
+ GList* listGraph;
+ gchar *frame_label = NULL;
+ gchar *comment = NULL;
+ graph_analysis_item_t *gai;
+ gboolean new = FALSE;
+ gboolean fromEndpoint = FALSE; /* true for calls originated in Endpoints, false for calls from MGC */
+ gdouble diff_time;
+
+ const mgcp_info_t *pi = MGCPinfo;
+
+
+ if ((pi->mgcp_type == MGCP_REQUEST) && !pi->is_duplicate ){
+ /* check wether we already have a call with this Endpoint and it is active*/
+ list = g_list_first(tapinfo->strinfo_list);
+ while (list)
+ {
+ tmp_listinfo=list->data;
+ if ((tmp_listinfo->protocol == VOIP_MGCP) && (tmp_listinfo->call_active_state == VOIP_ACTIVE)){
+ tmp_mgcpinfo = tmp_listinfo->prot_info;
+ if (pi->endpointId != NULL){
+ if (g_strcasecmp(tmp_mgcpinfo->endpointId,pi->endpointId) == 0){
+ /*
+ check first if it is an ended call. We consider an ended call after 1sec we don't
+ get a packet in this Endpoint and the call has been released
+ */
+ diff_time = (pinfo->fd->rel_secs + (double)pinfo->fd->rel_secs/1000000) - (tmp_listinfo->stop_sec + (double)tmp_listinfo->stop_usec/1000000);
+ if ( ((tmp_listinfo->call_state == VOIP_CANCELLED) || (tmp_listinfo->call_state == VOIP_COMPLETED) || (tmp_listinfo->call_state == VOIP_REJECTED)) && (diff_time > 1) ){
+ tmp_listinfo->call_active_state = VOIP_INACTIVE;
+ } else {
+ strinfo = (voip_calls_info_t*)(list->data);
+ break;
+ }
+ }
+ }
+ }
+ list = g_list_next (list);
+ }
+
+ /* there is no call with this Endpoint, lets see if this a new call or not */
+ if (strinfo == NULL){
+ if ( (strcmp(pi->code, "NTFY") == 0) && isSignal("hd", pi->observedEvents) ){ /* off hook transition */
+ /* this is a new call from the Endpoint */
+ fromEndpoint = TRUE;
+ new = TRUE;
+ } else if (strcmp(pi->code, "CRCX") == 0){
+ /* this is a new call from the MGC */
+ fromEndpoint = FALSE;
+ new = TRUE;
+ }
+ if (!new) return 0;
+ }
+ } else if ( ((pi->mgcp_type == MGCP_RESPONSE) && pi->request_available) ||
+ ((pi->mgcp_type == MGCP_REQUEST) && pi->is_duplicate) ) {
+ /* if it is a response OR if it is a duplicated Request, lets look in the Graph if thre is a request that match */
+ listGraph = g_list_first(tapinfo->graph_analysis->list);
+ while (listGraph)
+ {
+ gai = listGraph->data;
+ if (gai->frame_num == pi->req_num){
+ /* there is a request that match, so look the associated call with this call_num */
+ list = g_list_first(tapinfo->strinfo_list);
+ while (list)
+ {
+ tmp_listinfo=list->data;
+ if (tmp_listinfo->protocol == VOIP_MGCP){
+ if (tmp_listinfo->call_num == gai->conv_num){
+ tmp_mgcpinfo = tmp_listinfo->prot_info;
+ strinfo = (voip_calls_info_t*)(list->data);
+ break;
+ }
+ }
+ list = g_list_next (list);
+ }
+ if (strinfo != NULL) break;
+ }
+ listGraph = g_list_next(listGraph);
+ }
+ /* if there is not a matching request, just return */
+ if (strinfo == NULL) return 0;
+ } else return 0;
+
+ /* not in the list? then create a new entry */
+ if (strinfo==NULL){
+ strinfo = g_malloc(sizeof(voip_calls_info_t));
+ strinfo->call_active_state = VOIP_ACTIVE;
+ strinfo->call_state = VOIP_CALL_SETUP;
+ if (fromEndpoint) {
+ strinfo->from_identity=g_strdup(pi->endpointId);
+ strinfo->to_identity=g_strdup("");
+ } else {
+ strinfo->from_identity=g_strdup("");
+ strinfo->to_identity=g_strdup(pi->endpointId);
+ }
+ COPY_ADDRESS(&(strinfo->initial_speaker),&(pinfo->src));
+ strinfo->first_frame_num=pinfo->fd->num;
+ strinfo->selected=FALSE;
+ strinfo->start_sec=pinfo->fd->rel_secs;
+ strinfo->start_usec=pinfo->fd->rel_usecs;
+ strinfo->protocol=VOIP_MGCP;
+ strinfo->prot_info=g_malloc(sizeof(mgcp_calls_info_t));
+ tmp_mgcpinfo=strinfo->prot_info;
+ tmp_mgcpinfo->endpointId = g_strdup(pi->endpointId);
+ tmp_mgcpinfo->fromEndpoint = fromEndpoint;
+ strinfo->npackets = 0;
+ strinfo->call_num = tapinfo->ncalls++;
+ tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo);
+ }
+
+ g_assert(tmp_mgcpinfo != NULL);
+
+ /* change call state and add to graph */
+ switch (pi->mgcp_type)
+ {
+ case MGCP_REQUEST:
+ if ( (strcmp(pi->code, "NTFY") == 0) && (pi->observedEvents != NULL) ){
+ frame_label = g_strdup_printf("%s ObsEvt:%s",pi->code, pi->observedEvents);
+
+ if (tmp_mgcpinfo->fromEndpoint){
+ /* use the Dialed digits to fill the "To" for the call */
+ mgcpDialedDigits(pi->observedEvents, &(strinfo->to_identity));
+
+ /* from MGC and the user picked up, the call is connected */
+ } else if (isSignal("hd", pi->observedEvents))
+ strinfo->call_state=VOIP_IN_CALL;
+
+ /* hung up signal */
+ if (isSignal("hu", pi->observedEvents)) {
+ if ((strinfo->call_state == VOIP_CALL_SETUP) || (strinfo->call_state == VOIP_RINGING)){
+ strinfo->call_state = VOIP_CANCELLED;
+ } else {
+ strinfo->call_state = VOIP_COMPLETED;
+ }
+ }
+
+ } else if (strcmp(pi->code, "RQNT") == 0) {
+ /* for calls from Endpoint: if there is a "no signal" RQNT and the call was RINGING, we assume this is the CONNECT */
+ if ( tmp_mgcpinfo->fromEndpoint && isSignal("", pi->signalReq) && (strinfo->call_state == VOIP_RINGING) ) {
+ strinfo->call_state = VOIP_IN_CALL;
+ }
+
+ /* if there is ringback or ring tone, change state to ringing */
+ if ( isSignal("rg", pi->signalReq) || isSignal("rt", pi->signalReq) ) {
+ strinfo->call_state = VOIP_RINGING;
+ }
+
+ /* if there is a Busy or ReorderTone, and the call was Ringing or Setup the call is Rejected */
+ if ( (isSignal("ro", pi->signalReq) || isSignal("bz", pi->signalReq)) && ((strinfo->call_state == VOIP_CALL_SETUP) || (strinfo->call_state = VOIP_RINGING)) ) {
+ strinfo->call_state = VOIP_REJECTED;
+ }
+
+ if (pi->signalReq != NULL)
+ frame_label = g_strdup_printf("%s%sSigReq:%s",pi->code, (pi->hasDigitMap == TRUE)?" DigitMap ":"", pi->signalReq);
+ else
+ frame_label = g_strdup_printf("%s%s",pi->code, (pi->hasDigitMap == TRUE)?" DigitMap ":"");
+
+ /* use the CallerID info to fill the "From" for the call */
+ if (!tmp_mgcpinfo->fromEndpoint) mgcpCallerID(pi->signalReq, &(strinfo->from_identity));
+
+ } else if (strcmp(pi->code, "DLCX") == 0) {
+ /*
+ if there is a DLCX in a call To an Endpoint and the call was not connected, we use
+ the DLCX as the end of the call
+ */
+ if (!tmp_mgcpinfo->fromEndpoint){
+ if ((strinfo->call_state == VOIP_CALL_SETUP) || (strinfo->call_state == VOIP_RINGING)){
+ strinfo->call_state = VOIP_CANCELLED;
+ }
+ }
+ }
+
+ if (frame_label == NULL) frame_label = g_strdup_printf("%s",pi->code);
+ break;
+ case MGCP_RESPONSE:
+ frame_label = g_strdup_printf("%d (%s)",pi->rspcode, pi->code);
+ break;
+ case MGCP_OTHERS:
+ /* XXX what to do? */
+ break;
+ }
+
+
+ comment = g_strdup_printf("MGCP %s %s%s", tmp_mgcpinfo->endpointId, (pi->mgcp_type == MGCP_REQUEST)?"Request":"Response", pi->is_duplicate?" Duplicate":"");
+
+ strinfo->stop_sec=pinfo->fd->rel_secs;
+ strinfo->stop_usec=pinfo->fd->rel_usecs;
+ strinfo->last_frame_num=pinfo->fd->num;
+ ++(strinfo->npackets);
+ /* increment the packets counter of all calls */
+ ++(tapinfo->npackets);
+
+ /* add to the graph */
+ add_to_graph(tapinfo, pinfo, frame_label, comment, strinfo->call_num);
+ g_free(comment);
+ g_free(frame_label);
+
+ /* add SDP info if apply */
+ if ( (sdp_summary != NULL) && (sdp_frame_num == pinfo->fd->num) ){
+ append_to_frame_graph(tapinfo, pinfo->fd->num, sdp_summary, NULL);
+ g_free(sdp_summary);
+ sdp_summary = NULL;
+ }
+
+ return 1; /* refresh output */
+}
+
+
+/****************************************************************************/
+/* TAP INTERFACE */
+/****************************************************************************/
+static gboolean have_MGCP_tap_listener=FALSE;
+/****************************************************************************/
+void
+mgcp_calls_init_tap(void)
+{
+ GString *error_string;
+
+ if(have_MGCP_tap_listener==FALSE)
+ {
+ /* don't register tap listener, if we have it already */
+ /* we send an empty filter, to force a non null "tree" in the mgcp dissector */
+ error_string = register_tap_listener("mgcp", &(the_tapinfo_struct.mgcp_dummy), strdup(""),
+ voip_calls_dlg_reset,
+ MGCPcalls_packet,
+ voip_calls_dlg_draw
+ );
+ if (error_string != NULL) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+ have_MGCP_tap_listener=TRUE;
+ }
+}
+
+
+
+/* XXX just copied from gtk/rpc_stat.c */
+void protect_thread_critical_region(void);
+void unprotect_thread_critical_region(void);
+
+/****************************************************************************/
+void
+remove_tap_listener_mgcp_calls(void)
+{
+ protect_thread_critical_region();
+ remove_tap_listener(&(the_tapinfo_struct.mgcp_dummy));
+ unprotect_thread_critical_region();
+
+ have_MGCP_tap_listener=FALSE;
+}
+
/****************************************************************************/