Freetdm: Support for mapped raw traces

This commit is contained in:
David Yat Sin 2010-12-20 17:06:36 -05:00
parent d6ec16804a
commit 4144d518c6
5 changed files with 327 additions and 53 deletions

View File

@ -233,6 +233,7 @@ typedef struct sngisdn_chan_data {
uint32_t flags;
uint8_t ces; /* used only for BRI, otherwise always 0 */
uint8_t dchan_id;
uint16_t call_ref; /* Q.931 call reference, only valid for ETSI/INSNET/QSIG */
uint32_t suInstId; /* instance ID generated locally */
uint32_t spInstId; /* instance ID generated by stack */
@ -446,6 +447,9 @@ void sngisdn_rcv_cc_ind(CcMngmt *status);
void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...);
void sngisdn_rcv_sng_assert(char *message);
#ifdef NETBORDER_CALL_REF
ftdm_status_t get_callref(ftdm_channel_t *ftdmchan, BCCallRef* callRef);
#endif
ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
ftdm_status_t get_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
ftdm_status_t get_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb);

View File

@ -71,13 +71,12 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
sngisdn_info->glare.suInstId = suInstId; /* Do not generate a suInstId now, we will generate when glared call gets extracted */
sngisdn_info->glare.spInstId = spInstId;
sngisdn_info->glare.dChan = dChan;
sngisdn_info->glare.ces = ces;
sngisdn_info->glare.ces = ces;
break;
}
sngisdn_info->suInstId = get_unique_suInstId(suId);
sngisdn_info->spInstId = spInstId;
if (conEvnt->cdPtyNmb.eh.pres && signal_data->num_local_numbers) {
uint8_t local_number_matched = 0;
@ -125,6 +124,9 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
}
/* Fill in call information */
#ifdef NETBORDER_CALL_REF
get_callref(ftdmchan, &conEvnt->callRef);
#endif
get_calling_num(ftdmchan, &conEvnt->cgPtyNmb);
get_calling_num2(ftdmchan, &conEvnt->cgPtyNmb2);
get_called_num(ftdmchan, &conEvnt->cdPtyNmb);
@ -282,6 +284,7 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event)
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_DIALING:
get_callref(ftdmchan, &cnStEvnt->callRef);
get_prog_ind_ie(ftdmchan, &cnStEvnt->progInd);
get_facility_ie(ftdmchan, &cnStEvnt->facilityStr);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
@ -354,6 +357,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
case MI_CALLPROC:
case MI_PROGRESS:
case MI_ALERTING:
get_callref(ftdmchan, &cnStEvnt->callRef);
get_prog_ind_ie(ftdmchan, &cnStEvnt->progInd);
get_facility_ie(ftdmchan, &cnStEvnt->facilityStr);

View File

@ -161,6 +161,32 @@ ftdm_status_t sngisdn_set_span_avail_rate(ftdm_span_t *span, sngisdn_avail_t ava
return FTDM_SUCCESS;
}
#ifdef NETBORDER_CALL_REF
ftdm_status_t get_callref(ftdm_channel_t *ftdmchan, BCCallRef* callRef)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
if (signal_data->raw_trace_q931) {
if (callRef->eh.pres != PRSNT_NODEF || callRef->reference.pres != PRSNT_NODEF) {
/* Netborder only supports BRI, so we only care for BRI for now */
if (FTDM_SPAN_IS_BRI(ftdmchan->span) && !sngisdn_info->call_ref) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to obtain call reference\n");
}
return FTDM_FAIL;
}
if (FTDM_SPAN_IS_BRI(ftdmchan->span)) {
sngisdn_info->call_ref = 0x7F & callRef->reference.val;
} else {
sngisdn_info->call_ref = 0x7FFF & callRef->reference.val;
}
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Call reference:%04x\n", sngisdn_info->call_ref);
}
return FTDM_SUCCESS;
}
#endif
ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
{
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;

View File

@ -38,14 +38,26 @@
#define OCTET(x) (ieData[x-1] & 0xFF)
#define MAX_DECODE_STR_LEN 2000
typedef struct sngisdn_trace_info
{
uint8_t call_ref_flag;
uint16_t call_ref;
uint8_t msgtype;
uint8_t bchan_no;
ftdm_trace_dir_t dir;
} sngisdn_frame_info_t;
void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end);
uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset, uint8_t *data, uint16_t index_start);
static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_frame_info_t frame_info, ftdm_channel_t **found);
static ftdm_status_t sngisdn_get_frame_info(uint8_t *data, uint32_t data_len, ftdm_trace_dir_t dir, sngisdn_frame_info_t *frame_info);
uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi);
char* get_code_2_str(int code, struct code2str *pCodeTable);
void sngisdn_decode_q921(char* str, uint8_t* data, uint32_t data_len);
void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len);
char* get_code_2_str(int code, struct code2str *pCodeTable)
{
struct code2str* pCode2txt;
@ -120,10 +132,7 @@ void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
sigev.ev_data.trace.dir = dir;
sigev.ev_data.trace.type = FTDM_TRACE_TYPE_Q921;
/* TODO: Map trace to call ID here */
sigev.call_id = 0;
raw_data = ftdm_malloc(data_len);
ftdm_assert(raw_data, "Failed to malloc");
@ -218,26 +227,33 @@ void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
{
uint8_t *raw_data;
ftdm_sigmsg_t sigev;
ftdm_channel_t *ftdmchan;
sngisdn_frame_info_t frame_info;
memset(&sigev, 0, sizeof(sigev));
sigev.span_id = signal_data->ftdm_span->span_id;
sigev.chan_id = signal_data->dchan->chan_id;
sigev.channel = signal_data->dchan;
sigev.event_id = FTDM_SIGEVENT_TRACE_RAW;
/* Note: Mapped raw trace assume only exclusive b-channel selection is used. i.e the b-channel selected on outgoing SETUP is always used for the call */
if (sngisdn_get_frame_info(data, data_len, dir, &frame_info) == FTDM_SUCCESS) {
if (sngisdn_map_call(signal_data, frame_info, &ftdmchan) == FTDM_SUCCESS) {
sigev.call_id = ftdmchan->caller_data.call_id;
sigev.span_id = ftdmchan->physical_span_id;
sigev.chan_id = ftdmchan->physical_chan_id;
sigev.channel = ftdmchan;
}
sigev.event_id = FTDM_SIGEVENT_TRACE_RAW;
sigev.ev_data.trace.dir = dir;
sigev.ev_data.trace.type = FTDM_TRACE_TYPE_Q931;
/* TODO: Map trace to call ID here */
raw_data = ftdm_malloc(data_len);
ftdm_assert(raw_data, "Failed to malloc");
memcpy(raw_data, data, data_len);
sigev.raw_data = raw_data;
sigev.raw_data_len = data_len;
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
sigev.ev_data.trace.dir = dir;
sigev.ev_data.trace.type = FTDM_TRACE_TYPE_Q931;
raw_data = ftdm_malloc(data_len);
ftdm_assert(raw_data, "Failed to malloc");
memcpy(raw_data, data, data_len);
sigev.raw_data = raw_data;
sigev.raw_data_len = data_len;
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
}
}
void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len)
@ -253,9 +269,6 @@ void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len)
prot_disc = (uint8_t)data[0];
str_len += sprintf(&str[str_len], " Prot Disc:%s (0x%02x)\n", get_code_2_str(prot_disc, dcodQ931ProtDiscTable), prot_disc);
/* Decode Call Reference */
lenCallRef = (uint8_t) (data[1] & 0x0F);
@ -747,4 +760,203 @@ void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_
return;
}
static ftdm_status_t sngisdn_get_frame_info(uint8_t *data, uint32_t data_len, ftdm_trace_dir_t dir, sngisdn_frame_info_t *target)
{
uint8_t pos = 0;
uint8_t flag;
uint16_t ref = 0;
uint8_t ref_len = 0;
uint8_t bchan_no = 0;
uint8_t msgtype;
/* First octet is protocol discriminator */
pos++;
/* Second octet contains length of call reference */
ref_len = data[pos++] & 0x0F;
/* third octet is call reference */
flag = (data[pos] & 0x80) >> 7;
if (ref_len == 2) {
ref = (data[pos++] & 0x7F) << 8;
ref |= (data[pos++] & 0xFF) ;
} else {
ref = (data[pos++] & 0x7F);
}
/* Next octet is the message type */
msgtype = data[pos++] & 0x7F;
/*
ftdm_log(FTDM_LOG_DEBUG, "Raw frame:call_ref:0x%04x flag:%d msgtype:%d\n", ref, flag, msgtype);
*/
if (!ref) {
/* This is not a call specific message (RESTART for example and we do not care about it) */
return FTDM_FAIL;
}
/* Look for the b-channel */
if (msgtype == PROT_Q931_MSGTYPE_SETUP) {
/* Try to find the b-channel no*/
for(; pos < data_len; pos++) {
uint8_t ie_id = data[pos];
uint8_t ie_len = data[pos+1];
switch(ie_id) {
case PROT_Q931_IE_SENDING_COMPLETE:
/* Single octet ie's do not have a length */
ie_len = 0;
break;
case PROT_Q931_IE_CHANNEL_ID:
{
/* Try to obtain the b-channel */
uint8_t ie_pos = pos+2;
//ifaceIdPresent = get_bits(OCTET(3),7,7);
if (data[ie_pos] & 0x20) {
/* Interface type is Primary Rate */
ie_pos+=2;
bchan_no = data[ie_pos] & 0x7F;
} else {
/* Interface type is Basic Interface */
/* Get the channel number from info channel selection */
bchan_no = data[ie_pos] & 0x03;
}
ftdm_log(FTDM_LOG_DEBUG, "Found b-channel:%d\n", bchan_no);
goto parse_ies_done;
}
break;
default:
pos = pos+ie_len+1;
}
//ftdm_log(FTDM_LOG_DEBUG, "Decoded IE:%s\n", get_code_2_str(ie_id, dcodQ931IEIDTable));
}
if (!bchan_no) {
char tmp[1000];
print_hex_dump(tmp, 0, data, 0, data_len);
ftdm_log(FTDM_LOG_WARNING, "Failed to determine b-channel on SETUP message\n%s\n", tmp);
}
}
parse_ies_done:
target->call_ref = ref;
target->call_ref_flag = flag;
target->msgtype = msgtype;
target->bchan_no = bchan_no;
target->dir = dir;
return FTDM_SUCCESS;
}
static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_frame_info_t frame_info, ftdm_channel_t **found)
{
ftdm_channel_t *ftdmchan;
sngisdn_chan_data_t *sngisdn_info;
ftdm_iterator_t *chaniter = NULL;
ftdm_iterator_t *curr = NULL;
ftdm_status_t status = FTDM_FAIL;
uint8_t outbound_call = 0;
if ((!frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_OUTGOING) ||
(frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_INCOMING)) {
/* If this is an outgoing frame and this frame was sent by the originating side
of the call (frame_info.call_ref_flag == 0), then this is an outbound call */
outbound_call = 1;
} else {
outbound_call = 0;
}
switch (frame_info.msgtype) {
case PROT_Q931_MSGTYPE_SETUP:
/* We initiated this outgoing call try to match the call reference with our internal call-id*/
if (!frame_info.bchan_no) {
/* We were not able to determine the bchannel on this call, so we will not be able to match it anyway */
status = FTDM_FAIL;
}
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr));
ftdm_channel_lock(ftdmchan);
if (outbound_call) {
sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (ftdmchan->caller_data.call_id && ftdmchan->physical_chan_id == frame_info.bchan_no) {
sngisdn_info->call_ref = frame_info.call_ref;
*found = ftdmchan;
status = FTDM_SUCCESS;
}
}
} else {
if (ftdmchan->physical_chan_id == frame_info.bchan_no) {
*found = ftdmchan;
status = FTDM_SUCCESS;
}
}
ftdm_channel_unlock(ftdmchan);
}
ftdm_iterator_free(chaniter);
break;
case PROT_Q931_MSGTYPE_ALERTING:
case PROT_Q931_MSGTYPE_PROCEEDING:
case PROT_Q931_MSGTYPE_PROGRESS:
case PROT_Q931_MSGTYPE_CONNECT:
case PROT_Q931_MSGTYPE_SETUP_ACK:
case PROT_Q931_MSGTYPE_CONNECT_ACK:
case PROT_Q931_MSGTYPE_USER_INFO:
case PROT_Q931_MSGTYPE_DISCONNECT:
case PROT_Q931_MSGTYPE_RELEASE:
case PROT_Q931_MSGTYPE_RELEASE_ACK:
case PROT_Q931_MSGTYPE_RELEASE_COMPLETE:
case PROT_Q931_MSGTYPE_FACILITY:
case PROT_Q931_MSGTYPE_NOTIFY:
case PROT_Q931_MSGTYPE_STATUS_ENQUIRY:
case PROT_Q931_MSGTYPE_INFORMATION:
case PROT_Q931_MSGTYPE_STATUS:
/* Look for an outbound call on that span and and try to match the call-id */
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr));
ftdm_channel_lock(ftdmchan);
sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
if (outbound_call) {
if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (sngisdn_info->call_ref == frame_info.call_ref) {
*found = ftdmchan;
status = FTDM_SUCCESS;
}
}
} else {
if (sngisdn_info && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (sngisdn_info->call_ref && sngisdn_info->call_ref == frame_info.call_ref) {
*found = ftdmchan;
status = FTDM_SUCCESS;
}
}
}
ftdm_channel_unlock(ftdmchan);
}
ftdm_iterator_free(chaniter);
break;
default:
/* This frame is not call specific, ignore */
break;
}
if (status == FTDM_SUCCESS) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Mapped %s with Call Ref:%04x to call-id:%d\n", get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref, (*found)->caller_data.call_id);
} else {
/* We could not map this frame to a call-id */
ftdm_log(FTDM_LOG_DEBUG, "Failed to map %s with Call Ref:%04x to local call\n",
get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref);
}
return status;
}

View File

@ -191,37 +191,65 @@ struct code2str dcodQ931CallRefLoTable[] = {
{13, "D"},
{14, "E"},
{15, "F"},
{-1,"?"},
{-1, "?"},
};
#define PROT_Q931_MSGTYPE_ALERTING 1
#define PROT_Q931_MSGTYPE_PROCEEDING 2
#define PROT_Q931_MSGTYPE_PROGRESS 3
#define PROT_Q931_MSGTYPE_SETUP 5
#define PROT_Q931_MSGTYPE_CONNECT 7
#define PROT_Q931_MSGTYPE_SETUP_ACK 13
#define PROT_Q931_MSGTYPE_CONNECT_ACK 15
#define PROT_Q931_MSGTYPE_USER_INFO 32
#define PROT_Q931_MSGTYPE_SUSPEND_REJ 33
#define PROT_Q931_MSGTYPE_RESUME_REJ 34
#define PROT_Q931_MSGTYPE_SUSPEND 37
#define PROT_Q931_MSGTYPE_RESUME 38
#define PROT_Q931_MSGTYPE_SUSPEND_ACK 45
#define PROT_Q931_MSGTYPE_RESUME_ACK 46
#define PROT_Q931_MSGTYPE_DISCONNECT 69
#define PROT_Q931_MSGTYPE_RESTART 70
#define PROT_Q931_MSGTYPE_RELEASE 77
#define PROT_Q931_MSGTYPE_RELEASE_ACK 78
#define PROT_Q931_MSGTYPE_RELEASE_COMPLETE 90
#define PROT_Q931_MSGTYPE_SEGMENT 96
#define PROT_Q931_MSGTYPE_FACILITY 98
#define PROT_Q931_MSGTYPE_NOTIFY 110
#define PROT_Q931_MSGTYPE_STATUS_ENQUIRY 117
#define PROT_Q931_MSGTYPE_CONGESTION_CNTRL 121
#define PROT_Q931_MSGTYPE_INFORMATION 123
#define PROT_Q931_MSGTYPE_STATUS 125
struct code2str dcodQ931MsgTypeTable[] = {
{1, "Alerting"},
{2, "Call Proceeding"},
{3, "Progress"},
{5, "Setup"},
{7, "Connect"},
{13, "Setup Ack"},
{15, "Connect Ack"},
{32, "User Info"},
{33, "Suspend Rej"},
{34, "Resume Rej"},
{37, "Suspend"},
{38, "Resume"},
{45, "Suspend Ack"},
{46, "Resume Ack"},
{69, "Disconnect"},
{70, "Restart"},
{77, "Release"},
{78, "Release Ack"},
{90, "Release Compl"},
{96, "Segment"},
{98, "Facility"},
{110, "Notify"},
{117, "Status Enquiry"},
{121, "Congest Cntrl"},
{123, "Information"},
{125, "Status"},
{-1, "Unknown"},
{PROT_Q931_MSGTYPE_ALERTING, "ALERT"},
{PROT_Q931_MSGTYPE_PROCEEDING, "PROCEED"},
{PROT_Q931_MSGTYPE_PROGRESS, "PROGRESS"},
{PROT_Q931_MSGTYPE_SETUP, "SETUP"},
{PROT_Q931_MSGTYPE_CONNECT, "CONNECT"},
{PROT_Q931_MSGTYPE_SETUP_ACK, "SETUP ACK"},
{PROT_Q931_MSGTYPE_CONNECT_ACK, "CONNECT ACK"},
{PROT_Q931_MSGTYPE_USER_INFO, "USER INFO"},
{PROT_Q931_MSGTYPE_SUSPEND_REJ, "SUSPEND REJ"},
{PROT_Q931_MSGTYPE_RESUME_REJ, "RESUME REJ"},
{PROT_Q931_MSGTYPE_SUSPEND, "SUSPEND"},
{PROT_Q931_MSGTYPE_RESUME, "RESUME"},
{PROT_Q931_MSGTYPE_SUSPEND_ACK, "SUSPEND ACK"},
{PROT_Q931_MSGTYPE_RESUME_ACK, "RESUME ACK"},
{PROT_Q931_MSGTYPE_DISCONNECT, "DISCONNECT"},
{PROT_Q931_MSGTYPE_RESTART, "RESTART"},
{PROT_Q931_MSGTYPE_RELEASE, "RELEASE"},
{PROT_Q931_MSGTYPE_RELEASE_ACK, "RELEASR ACK"},
{PROT_Q931_MSGTYPE_RELEASE_COMPLETE, "RELEASE COMPLETE"},
{PROT_Q931_MSGTYPE_SEGMENT, "SEGMENT"},
{PROT_Q931_MSGTYPE_FACILITY, "FACILITY"},
{PROT_Q931_MSGTYPE_NOTIFY, "NOTIFY"},
{PROT_Q931_MSGTYPE_STATUS_ENQUIRY, "STATUS ENQ"},
{PROT_Q931_MSGTYPE_CONGESTION_CNTRL, "CONGESTION CTRL"},
{PROT_Q931_MSGTYPE_INFORMATION, "INFO"},
{PROT_Q931_MSGTYPE_STATUS, "STATUS"},
{-1, "UNKNOWN"},
};
struct code2str dcodQ931CauseCodeTable[] = {