From 44ed952a7b3c9f96c9f7fde11409b5c58501ccbf Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 16 Jan 2012 17:14:59 -0500 Subject: [PATCH] freetdm - ISDN support for sending Network Specific Facility --- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 2 + .../ftmod_sangoma_isdn_stack_hndl.c | 3 +- .../ftmod_sangoma_isdn_stack_out.c | 1 + .../ftmod_sangoma_isdn_support.c | 115 ++++++++++++++++++ .../ftmod_sangoma_isdn_trace.c | 2 +- .../ftmod_sangoma_isdn_user.h | 36 ++++++ 6 files changed, 157 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index a07f07e046..92054b8869 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -499,6 +499,7 @@ ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad); ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd); ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr); ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t data_len); +ftdm_status_t get_network_specific_fac(ftdm_channel_t *ftdmchan, NetFac *netFac); ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb); ftdm_status_t set_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb); @@ -508,6 +509,7 @@ ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt); ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad); ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_sngisdn_progind_t prog_ind); ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap); +ftdm_status_t set_network_specific_fac(ftdm_channel_t *ftdmchan, NetFac *netFac); ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId); ftdm_status_t set_restart_ind_ie(ftdm_channel_t *ftdmchan, RstInd *rstInd); ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index e95a582a45..5ff0b2a23f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -133,8 +133,9 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) get_redir_num(ftdmchan, &conEvnt->redirNmb); get_calling_subaddr(ftdmchan, &conEvnt->cgPtySad); get_prog_ind_ie(ftdmchan, &conEvnt->progInd); - get_facility_ie(ftdmchan, &conEvnt->facilityStr); + get_facility_ie(ftdmchan, &conEvnt->facilityStr); get_calling_name(ftdmchan, conEvnt); + get_network_specific_fac(ftdmchan, &conEvnt->netFac[0]); ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Incoming call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c index 7083fe25ec..327f1a7220 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c @@ -69,6 +69,7 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan) set_calling_subaddr(ftdmchan, &conEvnt.cgPtySad); set_redir_num(ftdmchan, &conEvnt.redirNmb); set_calling_name(ftdmchan, &conEvnt); + set_network_specific_fac(ftdmchan, &conEvnt.netFac[0]); /* set_facility_ie will overwrite Calling Name for NI-2 if user specifies custom Facility IE */ set_facility_ie(ftdmchan, &conEvnt.facilityStr); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index 70028e647d..bc53a42a7a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -43,6 +43,15 @@ SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_progind_descr, ftdm_sngisdn_progind_descr SNGISDN_ENUM_NAMES(SNGISDN_PROGIND_LOC_NAMES, SNGISDN_PROGIND_LOC_STRINGS) SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_progind_loc, ftdm_sngisdn_progind_loc2str, ftdm_sngisdn_progind_loc_t, SNGISDN_PROGIND_LOC_NAMES, SNGISDN_PROGIND_LOC_INVALID) +SNGISDN_ENUM_NAMES(SNGISDN_NETSPECFAC_TYPE_NAMES, SNGISDN_NETSPECFAC_TYPE_STRINGS) +SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_netspecfac_type, ftdm_sngisdn_netspecfac_type2str, ftdm_sngisdn_netspecfac_type_t, SNGISDN_NETSPECFAC_TYPE_NAMES, SNGISDN_NETSPECFAC_TYPE_INVALID) + +SNGISDN_ENUM_NAMES(SNGISDN_NETSPECFAC_PLAN_NAMES, SNGISDN_NETSPECFAC_PLAN_STRINGS) +SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_netspecfac_plan, ftdm_sngisdn_netspecfac_plan2str, ftdm_sngisdn_netspecfac_plan_t, SNGISDN_NETSPECFAC_PLAN_NAMES, SNGISDN_NETSPECFAC_PLAN_INVALID) + +SNGISDN_ENUM_NAMES(SNGISDN_NETSPECFAC_SPEC_NAMES, SNGISDN_NETSPECFAC_SPEC_STRINGS) +SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_netspecfac_spec, ftdm_sngisdn_netspecfac_spec2str, ftdm_sngisdn_netspecfac_spec_t, SNGISDN_NETSPECFAC_SPEC_NAMES, SNGISDN_NETSPECFAC_SPEC_INVALID) + static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t default_val); static uint8_t get_ftdm_val(ftdm2trillium_t *vals, uint8_t trillium_val, uint8_t default_val); ftdm_status_t get_calling_name_from_usr_usr(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr); @@ -71,6 +80,28 @@ ftdm2trillium_t ton_codes[] = { {FTDM_TON_RESERVED, IN_TON_EXT}, }; +ftdm2trillium_t nsf_spec_codes[] = { + {SNGISDN_NETSPECFAC_SPEC_ACCUNET, 0xe6}, + {SNGISDN_NETSPECFAC_SPEC_MEGACOM, 0xe3}, + {SNGISDN_NETSPECFAC_SPEC_MEGACOM_800, 0xe2}, + {SNGISDN_NETSPECFAC_SPEC_SDDN, 0xe1}, + {SNGISDN_NETSPECFAC_SPEC_INVALID, 0x00}, +}; + +ftdm2trillium_t nsf_type_codes[] = { + {SNGISDN_NETSPECFAC_TYPE_USER_SPEC, 0x00}, + {SNGISDN_NETSPECFAC_TYPE_NATIONAL_NETWORK_IDENT, 0x02}, + {SNGISDN_NETSPECFAC_TYPE_INTERNATIONAL_NETWORK_IDENT, 0x03}, + {SNGISDN_NETSPECFAC_TYPE_INVALID, 0x00}, +}; + +ftdm2trillium_t nsf_plan_codes[] = { + {SNGISDN_NETSPECFAC_PLAN_UNKNOWN, 0x00}, + {SNGISDN_NETSPECFAC_PLAN_CARRIER_IDENT, 0x01}, + {SNGISDN_NETSPECFAC_PLAN_DATA_NETWORK_IDENT, 0x03}, + {SNGISDN_NETSPECFAC_PLAN_INVALID, 0x00}, +}; + static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t default_val) { ftdm2trillium_t *val = vals; @@ -530,6 +561,29 @@ ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd) } +ftdm_status_t get_network_specific_fac(ftdm_channel_t *ftdmchan, NetFac *netFac) +{ + if (!netFac->eh.pres) { + return FTDM_FAIL; + } + + if (netFac->netFacSpec.pres == PRSNT_NODEF) { + char digits_string [32]; + memcpy(digits_string, (const char*)netFac->netFacSpec.val, netFac->netFacSpec.len); + digits_string[netFac->netFacSpec.len] = '\0'; + sngisdn_add_var((sngisdn_chan_data_t*)ftdmchan->call_data, "isdn.netFac.spec", digits_string); + } + + if (netFac->typeNetId.pres == PRSNT_NODEF) { + sngisdn_add_var((sngisdn_chan_data_t*)ftdmchan->call_data, "isdn.netFac.type", ftdm_sngisdn_netspecfac_type2str(get_ftdm_val(nsf_type_codes, netFac->typeNetId.val, 0x00))); + } + + if (netFac->netIdPlan.pres == PRSNT_NODEF) { + sngisdn_add_var((sngisdn_chan_data_t*)ftdmchan->call_data, "isdn.netFac.plan", ftdm_sngisdn_netspecfac_type2str(get_ftdm_val(nsf_plan_codes, netFac->netIdPlan.val, 0x00))); + } + return FTDM_SUCCESS; +} + ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; @@ -900,6 +954,67 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s return FTDM_SUCCESS; } +ftdm_status_t set_network_specific_fac(ftdm_channel_t *ftdmchan, NetFac *netFac) +{ + const char *str = NULL; + + str = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.netFac.spec"); + if (ftdm_strlen_zero(str)) { + /* Network-specific facility specification is mandatory, cannot send IE + without it */ + return FTDM_SUCCESS; + } else { + ftdm_sngisdn_netspecfac_spec_t spec = ftdm_str2ftdm_sngisdn_netspecfac_spec(str); + + netFac->eh.pres = PRSNT_NODEF; + netFac->netFacSpec.pres = PRSNT_NODEF; + + if (spec == SNGISDN_NETSPECFAC_SPEC_INVALID) { + int byte = 0; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Non-standard NSF specified:%s\n", str); + + if (sscanf(str, "%x", &byte) == 1) { + netFac->netFacSpec.val[0] = byte & 0xFF; + } + + netFac->netFacSpec.len = 1; + } else { + /* User is using one of the pre-specified NSF's */ + netFac->netFacSpec.val[0] = get_trillium_val(nsf_spec_codes, spec, 0x00); + netFac->netFacSpec.len = 1; + } + } + + netFac->lenNetId.pres = PRSNT_NODEF; + netFac->lenNetId.val = 0; + + str = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.netFac.type"); + if (!ftdm_strlen_zero(str)) { + netFac->typeNetId.pres = PRSNT_NODEF; + netFac->typeNetId.val = ftdm_str2ftdm_sngisdn_netspecfac_type(str); + } + + str = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.netFac.plan"); + if (!ftdm_strlen_zero(str)) { + netFac->netIdPlan.pres = PRSNT_NODEF; + netFac->netIdPlan.val = ftdm_str2ftdm_sngisdn_netspecfac_plan(str); + } + + if (netFac->netIdPlan.pres == PRSNT_NODEF || netFac->typeNetId.pres == PRSNT_NODEF) { + netFac->lenNetId.val++; + } + + str = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.netFac.ident"); + if (!ftdm_strlen_zero(str)) { + netFac->lenNetId.val++; + + netFac->netId.pres = PRSNT_NODEF; + memcpy(netFac->netId.val, str, strlen(str)); + } + + return FTDM_SUCCESS; +} + ftdm_status_t set_user_to_user_ie(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr) { sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c index 467ac7f9d8..52c4f4d321 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c @@ -771,7 +771,7 @@ uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset default: { *str_len += sprintf(&str[*str_len], "Undecoded"); - print_hex_dump((char*)str, str_len, data, index_start, index_end); + print_hex_dump((char*)str, str_len, data, index_start, index_end + 1); } break; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_user.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_user.h index 5d94e6c620..85cbc9b183 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_user.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_user.h @@ -101,6 +101,42 @@ typedef enum { #define SNGISDN_PROGIND_LOC_STRINGS "user", "private-net-local-user", "public-net-local-user", "transit-network", "public-net-remote-user", "private-net-remote-user", "beyond-interworking", "invalid" SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_progind_loc, ftdm_sngisdn_progind_loc2str, ftdm_sngisdn_progind_loc_t); +typedef enum { + /* User Specified */ + SNGISDN_NETSPECFAC_TYPE_USER_SPEC, + /* National network identification */ + SNGISDN_NETSPECFAC_TYPE_NATIONAL_NETWORK_IDENT, + /* International network identification */ + SNGISDN_NETSPECFAC_TYPE_INTERNATIONAL_NETWORK_IDENT, + /* Invalid */ + SNGISDN_NETSPECFAC_TYPE_INVALID, +} ftdm_sngisdn_netspecfac_type_t; +#define SNGISDN_NETSPECFAC_TYPE_STRINGS "user-specified", "national-network-identification", "national-network-identification", "invalid" +SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_netspecfac_type, ftdm_sngisdn_netspecfac_type2str, ftdm_sngisdn_netspecfac_type_t); + +typedef enum { + /* Unknown */ + SNGISDN_NETSPECFAC_PLAN_UNKNOWN, + /* Carrier Identification Code */ + SNGISDN_NETSPECFAC_PLAN_CARRIER_IDENT, + /* Data network identification code */ + SNGISDN_NETSPECFAC_PLAN_DATA_NETWORK_IDENT, + /* Invalid */ + SNGISDN_NETSPECFAC_PLAN_INVALID, +} ftdm_sngisdn_netspecfac_plan_t; +#define SNGISDN_NETSPECFAC_PLAN_STRINGS "unknown", "carrier-identification", "data-network-identification", "invalid" +SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_netspecfac_plan, ftdm_sngisdn_netspecfac_plan2str, ftdm_sngisdn_netspecfac_plan_t); + +typedef enum { + /* Unknown */ + SNGISDN_NETSPECFAC_SPEC_ACCUNET, + SNGISDN_NETSPECFAC_SPEC_MEGACOM, + SNGISDN_NETSPECFAC_SPEC_MEGACOM_800, + SNGISDN_NETSPECFAC_SPEC_SDDN, + SNGISDN_NETSPECFAC_SPEC_INVALID, +} ftdm_sngisdn_netspecfac_spec_t; +#define SNGISDN_NETSPECFAC_SPEC_STRINGS "accunet", "megacom", "megacom-800", "sddn", "invalid" +SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_netspecfac_spec, ftdm_sngisdn_netspecfac_spec2str, ftdm_sngisdn_netspecfac_spec_t); #endif /* __FTMOD_SANGOMA_ISDN_USER_H__*/