summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES12
-rw-r--r--UPGRADE.txt3
-rw-r--r--channels/chan_dahdi.c877
-rw-r--r--channels/chan_dahdi.h18
-rw-r--r--channels/sig_ss7.c1940
-rw-r--r--channels/sig_ss7.h100
-rw-r--r--configs/chan_dahdi.conf.sample51
-rw-r--r--configs/ss7.timers.sample65
-rwxr-xr-xconfigure6
-rw-r--r--configure.ac4
10 files changed, 2644 insertions, 432 deletions
diff --git a/CHANGES b/CHANGES
index 031533fd2..c3774fa6a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -20,6 +20,18 @@ AMI
res_manager_presence_state.so. If the high frequency of these events is
problematic for you, do not load these modules.
+chan_dahdi
+------------------
+ * SS7 support now requires libss7 v2.0 or later.
+
+ * Added SS7 support for connected line and redirecting.
+
+ * Most SS7 CLI commands are reworked as well as new SS7 commands added.
+ See online CLI help.
+
+ * Added several SS7 config option parameters described in
+ chan_dahdi.conf.sample.
+
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 12.3.0 to Asterisk 12.4.0 ------------
------------------------------------------------------------------------------
diff --git a/UPGRADE.txt b/UPGRADE.txt
index 9d3f46222..82dad8c2e 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -117,6 +117,9 @@ CDRs:
handler subroutine). In general, this is not the preferred default: this
causes extra CDRs to be generated for a channel in many common dialplans.
+chan_dahdi:
+ - SS7 support now requires libss7 v2.0 or later.
+
chan_sip:
- Made set SIPREFERREDBYHDR as inheritable for better chan_pjsip
interoperability.
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 71e5831e0..adc025ae0 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -81,7 +81,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#if defined(HAVE_SS7)
#include "sig_ss7.h"
-#if defined(LIBSS7_ABI_COMPATIBILITY)
+#if !defined(LIBSS7_ABI_COMPATIBILITY)
+#error "Upgrade your libss7"
+#elif LIBSS7_ABI_COMPATIBILITY != 2
#error "Your installed libss7 is not compatible"
#endif
#endif /* defined(HAVE_SS7) */
@@ -611,6 +613,7 @@ struct dahdi_ss7 {
static struct dahdi_ss7 linksets[NUM_SPANS];
static int cur_ss7type = -1;
+static int cur_slc = -1;
static int cur_linkset = -1;
static int cur_pointcode = -1;
static int cur_cicbeginswith = -1;
@@ -758,8 +761,8 @@ const char * const subnames[] = {
MEMBER(dahdi_pvt, mwimonitoractive, AST_DATA_BOOLEAN) \
MEMBER(dahdi_pvt, mwisendactive, AST_DATA_BOOLEAN) \
MEMBER(dahdi_pvt, inservice, AST_DATA_BOOLEAN) \
- MEMBER(dahdi_pvt, locallyblocked, AST_DATA_BOOLEAN) \
- MEMBER(dahdi_pvt, remotelyblocked, AST_DATA_BOOLEAN) \
+ MEMBER(dahdi_pvt, locallyblocked, AST_DATA_UNSIGNED_INTEGER) \
+ MEMBER(dahdi_pvt, remotelyblocked, AST_DATA_UNSIGNED_INTEGER) \
MEMBER(dahdi_pvt, manages_span_alarms, AST_DATA_BOOLEAN) \
MEMBER(dahdi_pvt, use_smdi, AST_DATA_BOOLEAN) \
MEMBER(dahdi_pvt, context, AST_DATA_STRING) \
@@ -873,7 +876,8 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
.internationalprefix = "",
.nationalprefix = "",
.subscriberprefix = "",
- .unknownprefix = ""
+ .unknownprefix = "",
+ .networkroutedprefix = ""
},
#endif /* defined(HAVE_SS7) */
#ifdef HAVE_OPENR2
@@ -3022,6 +3026,34 @@ static void my_ss7_set_loopback(void *pvt, int enable)
#if defined(HAVE_SS7)
/*!
* \internal
+ * \brief Find the linkset to which SS7 belongs.
+ * \since 11.0
+ *
+ * \param ss7 structure to match on.
+ *
+ * \retval linkset if found.
+ * \retval NULL if not found.
+ */
+static struct sig_ss7_linkset *my_ss7_find_linkset(struct ss7 *ss7)
+{
+ int idx;
+
+ if (!ss7) {
+ return NULL;
+ }
+
+ for (idx = 0; idx < NUM_SPANS; ++idx) {
+ if (linksets[idx].ss7.ss7 == ss7) {
+ return &linksets[idx].ss7;
+ }
+ }
+ return NULL;
+}
+#endif /* defined(HAVE_SS7) */
+
+#if defined(HAVE_SS7)
+/*!
+ * \internal
* \brief Create a new asterisk channel structure for SS7.
* \since 1.8
*
@@ -3128,6 +3160,7 @@ struct sig_ss7_callback sig_ss7_callbacks =
.set_callerid = my_set_callerid,
.set_dnid = my_set_dnid,
.open_media = my_pri_ss7_open_media,
+ .find_linkset = my_ss7_find_linkset,
};
#endif /* defined(HAVE_SS7) */
@@ -10688,9 +10721,10 @@ static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
break;
case MWI_SEND_SPILL:
/* We read some number of bytes. Write an equal amount of data */
- if(0 < num_read) {
- if (num_read > pvt->cidlen - pvt->cidpos)
+ if (0 < num_read) {
+ if (num_read > pvt->cidlen - pvt->cidpos) {
num_read = pvt->cidlen - pvt->cidpos;
+ }
res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read);
if (res > 0) {
pvt->cidpos += res;
@@ -10741,7 +10775,7 @@ static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
switch (event) {
case DAHDI_EVENT_RINGEROFF:
- if(pvt->mwisend_data.mwisend_current == MWI_SEND_SA_WAIT) {
+ if (pvt->mwisend_data.mwisend_current == MWI_SEND_SA_WAIT) {
handled = 1;
if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
@@ -11946,6 +11980,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
ast_copy_string(ss7->ss7.nationalprefix, conf->ss7.ss7.nationalprefix, sizeof(ss7->ss7.nationalprefix));
ast_copy_string(ss7->ss7.subscriberprefix, conf->ss7.ss7.subscriberprefix, sizeof(ss7->ss7.subscriberprefix));
ast_copy_string(ss7->ss7.unknownprefix, conf->ss7.ss7.unknownprefix, sizeof(ss7->ss7.unknownprefix));
+ ast_copy_string(ss7->ss7.networkroutedprefix, conf->ss7.ss7.networkroutedprefix, sizeof(ss7->ss7.networkroutedprefix));
ss7->ss7.called_nai = conf->ss7.ss7.called_nai;
ss7->ss7.calling_nai = conf->ss7.ss7.calling_nai;
@@ -12452,12 +12487,12 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
tmp->named_pickupgroups = ast_ref_namedgroups(conf->chan.named_pickupgroups);
if (conf->chan.vars) {
struct ast_variable *v, *tmpvar;
- for (v = conf->chan.vars ; v ; v = v->next) {
- if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
- tmpvar->next = tmp->vars;
- tmp->vars = tmpvar;
- }
- }
+ for (v = conf->chan.vars ; v ; v = v->next) {
+ if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
+ tmpvar->next = tmp->vars;
+ tmp->vars = tmpvar;
+ }
+ }
}
tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
@@ -12566,6 +12601,9 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
#if defined(HAVE_SS7)
case SIG_SS7:
tmp->inservice = 0;
+ if (tmp->ss7->flags & LINKSET_FLAG_INITIALHWBLO) {
+ tmp->remotelyblocked |= SS7_BLOCKED_HARDWARE;
+ }
break;
#endif /* defined(HAVE_SS7) */
default:
@@ -12600,6 +12638,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
case SIG_SS7:
if (ss7_chan) {
ss7_chan->inalarm = tmp->inalarm;
+ ss7_chan->inservice = tmp->inservice;
ss7_chan->stripmsd = tmp->stripmsd;
ss7_chan->hidecallerid = tmp->hidecallerid;
@@ -14891,6 +14930,9 @@ static int dahdi_restart(void)
}
ss7_set_error(dahdi_ss7_error);
ss7_set_message(dahdi_ss7_message);
+ ss7_set_hangup(sig_ss7_cb_hangup);
+ ss7_set_notinservice(sig_ss7_cb_notinservice);
+ ss7_set_call_null(sig_ss7_cb_call_null);
#endif /* defined(HAVE_SS7) */
if (setup_dahdi(2) != 0) {
@@ -14943,9 +14985,8 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
ast_group_t targetnum = 0;
int filtertype = 0;
struct dahdi_pvt *tmp = NULL;
- char tmps[20] = "";
- char statestr[20] = "";
- char blockstr[20] = "";
+ char tmps[20];
+ char blockstr[20];
switch (cmd) {
case CLI_INIT:
@@ -14961,8 +15002,9 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
/* syntax: dahdi show channels [ group <group> | context <context> ] */
- if (!((a->argc == 3) || (a->argc == 5)))
+ if (!((a->argc == 3) || (a->argc == 5))) {
return CLI_SHOWUSAGE;
+ }
if (a->argc == 5) {
if (!strcasecmp(a->argv[3], "group")) {
@@ -14977,7 +15019,7 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
}
}
- ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State", "Description");
+ ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Description");
ast_mutex_lock(&iflock);
for (tmp = iflist; tmp; tmp = tmp->next) {
if (filtertype) {
@@ -14998,24 +15040,15 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
}
if (tmp->channel > 0) {
snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
- } else
+ } else {
ast_copy_string(tmps, "pseudo", sizeof(tmps));
+ }
- if (tmp->locallyblocked)
- blockstr[0] = 'L';
- else
- blockstr[0] = ' ';
-
- if (tmp->remotelyblocked)
- blockstr[1] = 'R';
- else
- blockstr[1] = ' ';
-
+ blockstr[0] = tmp->locallyblocked ? 'L' : ' ';
+ blockstr[1] = tmp->remotelyblocked ? 'R' : ' ';
blockstr[2] = '\0';
- snprintf(statestr, sizeof(statestr), "%s", "In Service");
-
- ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr, tmp->description);
+ ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, tmp->inservice ? "Yes" : "No", tmp->description);
}
ast_mutex_unlock(&iflock);
return CLI_SUCCESS;
@@ -16023,7 +16056,7 @@ static int linkset_addsigchan(int sigchan)
(params.sigtype == DAHDI_SIG_MTP2)
? SS7_TRANSPORT_DAHDIMTP2
: SS7_TRANSPORT_DAHDIDCHAN,
- si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode);
+ si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode, cur_slc);
if (res) {
dahdi_close_ss7_fd(link, curfd);
return -1;
@@ -16049,8 +16082,11 @@ static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a
case CLI_GENERATE:
return NULL;
}
- if (a->argc < 6)
+
+ if (a->argc < 6) {
return CLI_SHOWUSAGE;
+ }
+
span = atoi(a->argv[5]);
if ((span < 1) || (span > NUM_SPANS)) {
ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[5], 1, NUM_SPANS);
@@ -16075,24 +16111,35 @@ static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a
#endif /* defined(HAVE_SS7) */
#if defined(HAVE_SS7)
-static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_ss7_cic_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int linkset, cic;
- int blocked = -1, i;
+ int blocked, i;
+ int do_block = 0;
+ unsigned int dpc;
+
switch (cmd) {
case CLI_INIT:
- e->command = "ss7 block cic";
+ e->command = "ss7 {block|unblock} cic";
e->usage =
- "Usage: ss7 block cic <linkset> <CIC>\n"
- " Sends a remote blocking request for the given CIC on the specified linkset\n";
+ "Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
+ " Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
- if (a->argc == 5)
+
+ if (a->argc == 6) {
linkset = atoi(a->argv[3]);
- else
+ } else {
return CLI_SHOWUSAGE;
+ }
+
+ if (!strcasecmp(a->argv[1], "block")) {
+ do_block = 1;
+ } else if (strcasecmp(a->argv[1], "unblock")) {
+ return CLI_SHOWUSAGE;
+ }
if ((linkset < 1) || (linkset > NUM_SPANS)) {
ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
@@ -16104,63 +16151,157 @@ static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_c
return CLI_SUCCESS;
}
- cic = atoi(a->argv[4]);
-
+ cic = atoi(a->argv[5]);
if (cic < 1) {
ast_cli(a->fd, "Invalid CIC specified!\n");
return CLI_SUCCESS;
}
+ dpc = atoi(a->argv[4]);
+ if (dpc < 1) {
+ ast_cli(a->fd, "Invalid DPC specified!\n");
+ return CLI_SUCCESS;
+ }
+
for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
- if (linksets[linkset-1].ss7.pvts[i]->cic == cic) {
+ if (linksets[linkset-1].ss7.pvts[i] && linksets[linkset-1].ss7.pvts[i]->cic == cic && linksets[linkset-1].ss7.pvts[i]->dpc == dpc) {
blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
- if (!blocked) {
- ast_mutex_lock(&linksets[linkset-1].ss7.lock);
- isup_blo(linksets[linkset-1].ss7.ss7, cic, linksets[linkset-1].ss7.pvts[i]->dpc);
- ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+ if (!do_block ^ !(blocked & SS7_BLOCKED_MAINTENANCE)) {
+ if (sig_ss7_cic_blocking(&linksets[linkset-1].ss7, do_block, i) < 0) {
+ ast_cli(a->fd, "Unable to allocate new ss7call\n");
+ } else {
+ ast_cli(a->fd, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block) ? "" : "un", linkset, cic, dpc);
+ }
+ } else if (!do_block && blocked) {
+ ast_cli(a->fd, "CIC %d is hardware locally blocked!\n", cic);
+ } else {
+ ast_cli(a->fd, "CIC %d %s locally blocked\n", cic, do_block ? "already" : "is not");
}
+ return CLI_SUCCESS;
}
}
- if (blocked < 0) {
- ast_cli(a->fd, "Invalid CIC specified!\n");
+ ast_cli(a->fd, "Invalid CIC specified!\n");
+ return CLI_SUCCESS;
+}
+#endif /* defined(HAVE_SS7) */
+
+#if defined(HAVE_SS7)
+static char *handle_ss7_linkset_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int linkset, i;
+ enum {
+ DO_BLOCK,
+ DO_UNBLOCK,
+ DO_RESET,
+ } do_what;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ss7 {reset|block|unblock} linkset";
+ e->usage =
+ "Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
+ " Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc == 4) {
+ linkset = atoi(a->argv[3]);
+ } else {
+ return CLI_SHOWUSAGE;
+ }
+
+ if (!strcasecmp(a->argv[1], "block")) {
+ do_what = DO_BLOCK;
+ } else if (!strcasecmp(a->argv[1], "unblock")) {
+ do_what = DO_UNBLOCK;
+ } else if (!strcasecmp(a->argv[1], "reset")) {
+ do_what = DO_RESET;
+ } else {
+ return CLI_SHOWUSAGE;
+ }
+
+ if ((linkset < 1) || (linkset > NUM_SPANS)) {
+ ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
return CLI_SUCCESS;
}
- if (!blocked)
- ast_cli(a->fd, "Sent blocking request for linkset %d on CIC %d\n", linkset, cic);
- else
- ast_cli(a->fd, "CIC %d already locally blocked\n", cic);
+ if (!linksets[linkset - 1].ss7.ss7) {
+ ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
+ return CLI_SUCCESS;
+ }
- /* Break poll on the linkset so it sends our messages */
- pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+ for (i = 0; i < linksets[linkset - 1].ss7.numchans; i++) {
+ /* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
+ if (linksets[linkset - 1].ss7.pvts[i]) {
+ switch (do_what) {
+ case DO_BLOCK:
+ case DO_UNBLOCK:
+ if (sig_ss7_cic_blocking(&linksets[linkset - 1].ss7, do_what == DO_BLOCK, i)) {
+ ast_cli(a->fd, "Sent remote %s request on CIC %d\n",
+ (do_what == DO_BLOCK) ? "blocking" : "unblocking",
+ linksets[linkset - 1].ss7.pvts[i]->cic);
+ }
+ break;
+ case DO_RESET:
+ if (sig_ss7_reset_cic(&linksets[linkset - 1].ss7,
+ linksets[linkset - 1].ss7.pvts[i]->cic,
+ linksets[linkset - 1].ss7.pvts[i]->dpc)) {
+ ast_cli(a->fd, "Sent reset request on CIC %d\n",
+ linksets[linkset - 1].ss7.pvts[i]->cic);
+ }
+ break;
+ }
+ }
+ }
return CLI_SUCCESS;
}
#endif /* defined(HAVE_SS7) */
#if defined(HAVE_SS7)
-static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_ss7_group_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
- int linkset;
- int i;
+ int linkset, cic, range, chanpos;
+ int i, dpc, orient = 0;
+ int do_block = 0;
+ unsigned char state[255];
+
switch (cmd) {
case CLI_INIT:
- e->command = "ss7 block linkset";
+ e->command = "ss7 {block|unblock} group";
e->usage =
- "Usage: ss7 block linkset <linkset number>\n"
- " Sends a remote blocking request for all CICs on the given linkset\n";
+ "Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
+ " Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
- if (a->argc == 4)
+
+ if (a->argc == 7 || a->argc == 8) {
linkset = atoi(a->argv[3]);
- else
+ } else {
return CLI_SHOWUSAGE;
+ }
+
+ if (!strcasecmp(a->argv[1], "block")) {
+ do_block = 1;
+ } else if (strcasecmp(a->argv[1], "unblock")) {
+ return CLI_SHOWUSAGE;
+ }
+
+ if (a->argc == 8) {
+ if (!strcasecmp(a->argv[7], "H")) {
+ orient = 1;
+ } else {
+ return CLI_SHOWUSAGE;
+ }
+ }
if ((linkset < 1) || (linkset > NUM_SPANS)) {
- ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
+ ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
return CLI_SUCCESS;
}
@@ -16169,43 +16310,81 @@ static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct a
return CLI_SUCCESS;
}
- for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
- ast_cli(a->fd, "Sending remote blocking request on CIC %d\n", linksets[linkset-1].ss7.pvts[i]->cic);
- ast_mutex_lock(&linksets[linkset-1].ss7.lock);
- isup_blo(linksets[linkset-1].ss7.ss7, linksets[linkset-1].ss7.pvts[i]->cic, linksets[linkset-1].ss7.pvts[i]->dpc);
+ cic = atoi(a->argv[5]);
+ if (cic < 1) {
+ ast_cli(a->fd, "Invalid CIC specified!\n");
+ return CLI_SUCCESS;
+ }
+
+ range = atoi(a->argv[6]);
+ /* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
+ if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
+ ast_cli(a->fd, "Invalid range specified!\n");
+ return CLI_SUCCESS;
+ }
+
+ dpc = atoi(a->argv[4]);
+ if (dpc < 1) {
+ ast_cli(a->fd, "Invalid DPC specified!\n");
+ return CLI_SUCCESS;
+ }
+
+ ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+ if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+ ast_cli(a->fd, "Invalid CIC/RANGE\n");
+ return CLI_SHOWUSAGE;
}
- /* Break poll on the linkset so it sends our messages */
- pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+ memset(state, 0, sizeof(state));
+ for (i = 0; i <= range; ++i) {
+ state[i] = 1;
+ }
+ /* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
+ chanpos = sig_ss7_find_cic(&linksets[linkset-1].ss7, cic, dpc);
+ if (sig_ss7_group_blocking(&linksets[linkset-1].ss7, do_block, chanpos, cic + range, state, orient)) {
+ ast_cli(a->fd, "Unable allocate new ss7call\n");
+ } else {
+ ast_cli(a->fd, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
+ orient ? " hardware" : "", do_block ? "" : "un", linkset, cic, range);
+ }
+
+ ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+
+ /* Break poll on the linkset so it sends our messages */
+ if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
+ pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+ }
return CLI_SUCCESS;
}
#endif /* defined(HAVE_SS7) */
#if defined(HAVE_SS7)
-static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_ss7_group_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
- int linkset, cic;
- int i, blocked = -1;
+ int linkset, cic, range;
+ unsigned int dpc;
+
switch (cmd) {
case CLI_INIT:
- e->command = "ss7 unblock cic";
+ e->command = "ss7 reset group";
e->usage =
- "Usage: ss7 unblock cic <linkset> <CIC>\n"
- " Sends a remote unblocking request for the given CIC on the specified linkset\n";
+ "Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
+ " Send a GRS for the given CIC range on the specified linkset\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
- if (a->argc == 5)
+ if (a->argc == 7) {
linkset = atoi(a->argv[3]);
- else
+ } else {
return CLI_SHOWUSAGE;
+ }
if ((linkset < 1) || (linkset > NUM_SPANS)) {
- ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
+ ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
return CLI_SUCCESS;
}
@@ -16214,54 +16393,69 @@ static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast
return CLI_SUCCESS;
}
- cic = atoi(a->argv[4]);
+ cic = atoi(a->argv[5]);
if (cic < 1) {
ast_cli(a->fd, "Invalid CIC specified!\n");
return CLI_SUCCESS;
}
- for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
- if (linksets[linkset-1].ss7.pvts[i]->cic == cic) {
- blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
- if (blocked) {
- ast_mutex_lock(&linksets[linkset-1].ss7.lock);
- isup_ubl(linksets[linkset-1].ss7.ss7, cic, linksets[linkset-1].ss7.pvts[i]->dpc);
- ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
- }
- }
+ range = atoi(a->argv[6]);
+ if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
+ ast_cli(a->fd, "Invalid range specified!\n");
+ return CLI_SUCCESS;
}
- if (blocked > 0)
- ast_cli(a->fd, "Sent unblocking request for linkset %d on CIC %d\n", linkset, cic);
+ dpc = atoi(a->argv[4]);
+ if (dpc < 1) {
+ ast_cli(a->fd, "Invalid DPC specified!\n");
+ return CLI_SUCCESS;
+ }
- /* Break poll on the linkset so it sends our messages */
- pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+ ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+ if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
+ ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+ ast_cli(a->fd, "Invalid CIC/RANGE\n");
+ return CLI_SHOWUSAGE;
+ }
+ if (sig_ss7_reset_group(&linksets[linkset-1].ss7, cic, dpc, range)) {
+ ast_cli(a->fd, "Unable to allocate new ss7call\n");
+ } else {
+ ast_cli(a->fd, "GRS sent ... \n");
+ }
+
+ ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+
+ /* Break poll on the linkset so it sends our messages */
+ if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
+ pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+ }
return CLI_SUCCESS;
}
#endif /* defined(HAVE_SS7) */
#if defined(HAVE_SS7)
-static char *handle_ss7_unblock_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_ss7_show_calls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int linkset;
- int i;
+
switch (cmd) {
case CLI_INIT:
- e->command = "ss7 unblock linkset";
+ e->command = "ss7 show calls";
e->usage =
- "Usage: ss7 unblock linkset <linkset number>\n"
- " Sends a remote unblocking request for all CICs on the specified linkset\n";
+ "Usage: ss7 show calls <linkset>\n"
+ " Show SS7 calls on the specified linkset\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
- if (a->argc == 4)
+ if (a->argc == 4) {
linkset = atoi(a->argv[3]);
- else
+ } else {
return CLI_SHOWUSAGE;
+ }
if ((linkset < 1) || (linkset > NUM_SPANS)) {
ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
@@ -16273,15 +16467,164 @@ static char *handle_ss7_unblock_linkset(struct ast_cli_entry *e, int cmd, struct
return CLI_SUCCESS;
}
- for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
- ast_cli(a->fd, "Sending remote unblock request on CIC %d\n", linksets[linkset-1].ss7.pvts[i]->cic);
- ast_mutex_lock(&linksets[linkset-1].ss7.lock);
- isup_ubl(linksets[linkset-1].ss7.ss7, linksets[linkset-1].ss7.pvts[i]->cic, linksets[linkset-1].ss7.pvts[i]->dpc);
- ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+ ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+ isup_show_calls(linksets[linkset-1].ss7.ss7, &ast_cli, a->fd);
+ ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+
+ return CLI_SUCCESS;
+}
+#endif /* defined(HAVE_SS7) */
+
+#if defined(HAVE_SS7)
+static char *handle_ss7_reset_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int linkset, cic, res;
+ unsigned int dpc;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ss7 reset cic";
+ e->usage =
+ "Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
+ " Send a RSC for the given CIC on the specified linkset\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc == 6) {
+ linkset = atoi(a->argv[3]);
+ } else {
+ return CLI_SHOWUSAGE;
+ }
+
+ if ((linkset < 1) || (linkset > NUM_SPANS)) {
+ ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
+ return CLI_SUCCESS;
+ }
+
+ if (!linksets[linkset-1].ss7.ss7) {
+ ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
+ return CLI_SUCCESS;
+ }
+
+ cic = atoi(a->argv[5]);
+
+ if (cic < 1) {
+ ast_cli(a->fd, "Invalid CIC specified!\n");
+ return CLI_SUCCESS;
+ }
+
+ dpc = atoi(a->argv[4]);
+ if (dpc < 1) {
+ ast_cli(a->fd, "Invalid DPC specified!\n");
+ return CLI_SUCCESS;
+ }
+
+ res = sig_ss7_reset_cic(&linksets[linkset-1].ss7, cic, dpc);
+
+ ast_cli(a->fd, "%s RSC for linkset %d on CIC %d DPC %d\n", res ? "Sent" : "Failed", linkset, cic, dpc);
+
+ return CLI_SUCCESS;
+}
+#endif /* defined(HAVE_SS7) */
+
+#if defined(HAVE_SS7)
+static char *handle_ss7_net_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int linkset;
+ unsigned int slc;
+ unsigned int arg = 0;
+ const char *res;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ss7 mtp3";
+ e->usage =
+ "Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
+ " Send a NET MNG message\n"
+ " WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc < 5) {
+ return CLI_SHOWUSAGE;
}
+ linkset = atoi(a->argv[2]);
+ if ((linkset < 1) || (linkset > NUM_SPANS)) {
+ ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
+ return CLI_SUCCESS;
+ }
+ if (!linksets[linkset-1].ss7.ss7) {
+ ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
+ return CLI_SUCCESS;
+ }
+
+ slc = atoi(a->argv[3]);
+
+ if (a->argc == 6) {
+ arg = atoi(a->argv[5]);
+ }
+
+ ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+ res = mtp3_net_mng(linksets[linkset-1].ss7.ss7, slc, a->argv[4], arg);
+ ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+
/* Break poll on the linkset so it sends our messages */
- pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+ if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
+ pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+ }
+
+ ast_cli(a->fd, "%s", res);
+
+ return CLI_SUCCESS;
+}
+#endif /* defined(HAVE_SS7) */
+
+#if defined(HAVE_SS7)
+static char *handle_ss7_mtp3_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int linkset;
+ unsigned int slc = 0;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ss7 restart mtp3";
+ e->usage =
+ "Usage: ss7 restart mtp3 <linkset> <slc>\n"
+ " Restart link\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc < 5) {
+ return CLI_SHOWUSAGE;
+ }
+
+ linkset = atoi(a->argv[3]);
+ if ((linkset < 1) || (linkset > NUM_SPANS)) {
+ ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
+ return CLI_SUCCESS;
+ }
+ if (!linksets[linkset-1].ss7.ss7) {
+ ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
+ return CLI_SUCCESS;
+ }
+
+ slc = atoi(a->argv[4]);
+
+ ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+ mtp3_init_restart(linksets[linkset-1].ss7.ss7, slc);
+ ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+
+ /* Break poll on the linkset so it sends our messages */
+ if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
+ pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+ }
return CLI_SUCCESS;
}
@@ -16303,8 +16646,10 @@ static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct as
return NULL;
}
- if (a->argc < 4)
+ if (a->argc < 4) {
return CLI_SHOWUSAGE;
+ }
+
linkset = atoi(a->argv[3]);
if ((linkset < 1) || (linkset > NUM_SPANS)) {
ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
@@ -16316,7 +16661,16 @@ static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct as
return CLI_SUCCESS;
}
+ ast_cli(a->fd, "SS7 flags: 0x%x\n", ss7->flags);
ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
+ ast_cli(a->fd, "SS7 calling nai: %i\n", ss7->calling_nai);
+ ast_cli(a->fd, "SS7 called nai: %i\n", ss7->called_nai);
+ ast_cli(a->fd, "SS7 nationalprefix: %s\n", ss7->nationalprefix);
+ ast_cli(a->fd, "SS7 internationalprefix: %s\n", ss7->internationalprefix);
+ ast_cli(a->fd, "SS7 unknownprefix: %s\n", ss7->unknownprefix);
+ ast_cli(a->fd, "SS7 networkroutedprefix: %s\n", ss7->networkroutedprefix);
+ ast_cli(a->fd, "SS7 subscriberprefix: %s\n", ss7->subscriberprefix);
+ ss7_show_linkset(ss7->ss7, &ast_cli, a->fd);
return CLI_SUCCESS;
}
@@ -16338,8 +16692,9 @@ static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct a
return NULL;
}
- if (a->argc != 3)
+ if (a->argc != 3) {
return CLI_SHOWUSAGE;
+ }
sig_ss7_cli_show_channels_header(a->fd);
for (linkset = 0; linkset < NUM_SPANS; ++linkset) {
@@ -16352,6 +16707,110 @@ static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct a
#endif /* defined(HAVE_SS7) */
#if defined(HAVE_SS7)
+static char *handle_ss7_show_cics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT "%5s %5s %6s %12s %-12s\n"
+#define FORMAT2 "%5i %5i %6i %12s %-12s\n"
+ int i, linkset, dpc = 0;
+ struct sig_ss7_linkset *ss7;
+ char *state;
+ char blocking[12];
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ss7 show cics";
+ e->usage =
+ "Usage: ss7 show cics <linkset> [dpc]\n"
+ " Shows the cics of an SS7 linkset.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc < 4 || a->argc > 5) {
+ return CLI_SHOWUSAGE;
+ }
+
+ linkset = atoi(a->argv[3]);
+
+ if ((linkset < 1) || (linkset > NUM_SPANS)) {
+ ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
+ return CLI_SUCCESS;
+ }
+
+ if (!linksets[linkset-1].ss7.ss7) {
+ ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
+ return CLI_SUCCESS;
+ }
+ ss7 = &linksets[linkset-1].ss7;
+
+ if (a->argc == 5) {
+ dpc = atoi(a->argv[4]);
+ if (dpc < 1) {
+ ast_cli(a->fd, "Invalid DPC specified!\n");
+ return CLI_SUCCESS;
+ }
+ }
+
+ ast_cli(a->fd, FORMAT, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
+
+ for (i = 0; i < ss7->numchans; i++) {
+ if (!dpc || (ss7->pvts[i] && ss7->pvts[i]->dpc == dpc)) {
+ struct dahdi_pvt *p = ss7->pvts[i]->chan_pvt;
+
+ if (ss7->pvts[i]->owner) {
+ state = "Used";
+ } else if (ss7->pvts[i]->ss7call) {
+ state = "Pending";
+ } else if (!p->inservice) {
+ state = "NotInServ";
+ } else {
+ state = "Idle";
+ }
+
+ if (p->locallyblocked) {
+ strcpy(blocking, "L:");
+ if (p->locallyblocked & SS7_BLOCKED_MAINTENANCE) {
+ strcat(blocking, "M");
+ } else {
+ strcat(blocking, " ");
+ }
+
+ if (p->locallyblocked & SS7_BLOCKED_HARDWARE) {
+ strcat(blocking, "H");
+ } else {
+ strcat(blocking, " ");
+ }
+ } else {
+ strcpy(blocking, " ");
+ }
+
+ if (p->remotelyblocked) {
+ strcat(blocking, " R:");
+ if (p->remotelyblocked & SS7_BLOCKED_MAINTENANCE) {
+ strcat(blocking, "M");
+ } else {
+ strcat(blocking, " ");
+ }
+
+ if (p->remotelyblocked & SS7_BLOCKED_HARDWARE) {
+ strcat(blocking, "H");
+ } else {
+ strcat(blocking, " ");
+ }
+ }
+
+ ast_cli(a->fd, FORMAT2, ss7->pvts[i]->cic, ss7->pvts[i]->dpc, ss7->pvts[i]->channel, state, blocking);
+ }
+ }
+
+ return CLI_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+#endif /* defined(HAVE_SS7) */
+
+#if defined(HAVE_SS7)
static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
switch (cmd) {
@@ -16374,12 +16833,17 @@ static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli
#if defined(HAVE_SS7)
static struct ast_cli_entry dahdi_ss7_cli[] = {
AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"),
- AST_CLI_DEFINE(handle_ss7_block_cic, "Blocks the given CIC"),
- AST_CLI_DEFINE(handle_ss7_unblock_cic, "Unblocks the given CIC"),
- AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"),
- AST_CLI_DEFINE(handle_ss7_unblock_linkset, "Unblocks all CICs on a linkset"),
+ AST_CLI_DEFINE(handle_ss7_cic_blocking, "Blocks/Unblocks the given CIC"),
+ AST_CLI_DEFINE(handle_ss7_linkset_mng, "Resets/Blocks/Unblocks all CICs on a linkset"),
+ AST_CLI_DEFINE(handle_ss7_group_blocking, "Blocks/Unblocks the given CIC range"),
+ AST_CLI_DEFINE(handle_ss7_reset_cic, "Resets the given CIC"),
+ AST_CLI_DEFINE(handle_ss7_group_reset, "Resets the given CIC range"),
+ AST_CLI_DEFINE(handle_ss7_mtp3_restart, "Restart a link"),
+ AST_CLI_DEFINE(handle_ss7_net_mng, "Send an NET MNG message"),
AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
AST_CLI_DEFINE(handle_ss7_show_channels, "Displays SS7 channel information"),
+ AST_CLI_DEFINE(handle_ss7_show_calls, "Show ss7 calls"),
+ AST_CLI_DEFINE(handle_ss7_show_cics, "Show cics on a linkset"),
AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
};
#endif /* defined(HAVE_SS7) */
@@ -16581,6 +17045,10 @@ static int __unload_module(void)
for (j = 0; j < SIG_SS7_NUM_DCHANS; j++) {
dahdi_close_ss7_fd(&(linksets[i]), j);
}
+ if (linksets[i].ss7.ss7) {
+ ss7_destroy(linksets[i].ss7.ss7);
+ linksets[i].ss7.ss7 = NULL;
+ }
}
#endif /* defined(HAVE_SS7) */
ast_cond_destroy(&ss_thread_complete);
@@ -16856,7 +17324,7 @@ static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_patte
for (; ;) {
/* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
- if(!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
+ if (!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
break;
}
@@ -17220,23 +17688,23 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
#else
/* Default is fsk, to turn it off you must specify nofsk */
memset(&confp->chan.mwisend_setting, 0, sizeof(confp->chan.mwisend_setting));
- if (strcasestr(v->value, "nofsk")) { /* NoFSK */
+ if (strcasestr(v->value, "nofsk")) { /* NoFSK */
confp->chan.mwisend_fsk = 0;
} else { /* Default FSK */
confp->chan.mwisend_fsk = 1;
}
- if (strcasestr(v->value, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
+ if (strcasestr(v->value, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
confp->chan.mwisend_rpas = 1;
} else {
confp->chan.mwisend_rpas = 0;
}
- if (strcasestr(v->value, "lrev")) { /* Line Reversal */
+ if (strcasestr(v->value, "lrev")) { /* Line Reversal */
confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_LREV;
}
- if (strcasestr(v->value, "hvdc")) { /* HV 90VDC */
+ if (strcasestr(v->value, "hvdc")) { /* HV 90VDC */
confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVDC;
}
- if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ){ /* 90V DC pulses */
+ if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ) { /* 90V DC pulses */
confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVAC;
}
#endif
@@ -17744,8 +18212,11 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
cur_ss7type = SS7_ITU;
} else if (!strcasecmp(v->value, "ansi")) {
cur_ss7type = SS7_ANSI;
- } else
+ } else {
ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
+ }
+ } else if (!strcasecmp(v->name, "slc")) {
+ cur_slc = atoi(v->value);
} else if (!strcasecmp(v->name, "linkset")) {
cur_linkset = atoi(v->value);
} else if (!strcasecmp(v->name, "pointcode")) {
@@ -17757,16 +18228,17 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
} else if (!strcasecmp(v->name, "cicbeginswith")) {
cur_cicbeginswith = atoi(v->value);
} else if (!strcasecmp(v->name, "networkindicator")) {
- if (!strcasecmp(v->value, "national"))
+ if (!strcasecmp(v->value, "national")) {
cur_networkindicator = SS7_NI_NAT;
- else if (!strcasecmp(v->value, "national_spare"))
+ } else if (!strcasecmp(v->value, "national_spare")) {
cur_networkindicator = SS7_NI_NAT_SPARE;
- else if (!strcasecmp(v->value, "international"))
+ } else if (!strcasecmp(v->value, "international")) {
cur_networkindicator = SS7_NI_INT;
- else if (!strcasecmp(v->value, "international_spare"))
+ } else if (!strcasecmp(v->value, "international_spare")) {
cur_networkindicator = SS7_NI_INT_SPARE;
- else
+ } else {
cur_networkindicator = -1;
+ }
} else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
ast_copy_string(confp->ss7.ss7.internationalprefix, v->value, sizeof(confp->ss7.ss7.internationalprefix));
} else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
@@ -17775,6 +18247,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
ast_copy_string(confp->ss7.ss7.subscriberprefix, v->value, sizeof(confp->ss7.ss7.subscriberprefix));
} else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
ast_copy_string(confp->ss7.ss7.unknownprefix, v->value, sizeof(confp->ss7.ss7.unknownprefix));
+ } else if (!strcasecmp(v->name, "ss7_networkroutedprefix")) {
+ ast_copy_string(confp->ss7.ss7.networkroutedprefix, v->value, sizeof(confp->ss7.ss7.networkroutedprefix));
} else if (!strcasecmp(v->name, "ss7_called_nai")) {
if (!strcasecmp(v->value, "national")) {
confp->ss7.ss7.called_nai = SS7_NAI_NATIONAL;
@@ -17807,9 +18281,9 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
int sigchan, res;
sigchan = atoi(v->value);
res = linkset_addsigchan(sigchan);
- if (res < 0)
+ if (res < 0) {
return -1;
-
+ }
} else if (!strcasecmp(v->name, "ss7_explicitacm")) {
struct dahdi_ss7 *link;
link = ss7_resolve_linkset(cur_linkset);
@@ -17817,8 +18291,148 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
return -1;
}
- if (ast_true(v->value))
+ if (ast_true(v->value)) {
link->ss7.flags |= LINKSET_FLAG_EXPLICITACM;
+ } else {
+ link->ss7.flags &= ~LINKSET_FLAG_EXPLICITACM;
+ }
+ } else if (!strcasecmp(v->name, "ss7_autoacm")) {
+ struct dahdi_ss7 *link;
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (ast_true(v->value)) {
+ link->ss7.flags |= LINKSET_FLAG_AUTOACM;
+ } else {
+ link->ss7.flags &= ~LINKSET_FLAG_AUTOACM;
+ }
+ } else if (!strcasecmp(v->name, "ss7_initialhwblo")) {
+ struct dahdi_ss7 *link;
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (ast_true(v->value)) {
+ link->ss7.flags |= LINKSET_FLAG_INITIALHWBLO;
+ } else {
+ link->ss7.flags &= ~LINKSET_FLAG_INITIALHWBLO;
+ }
+ } else if (!strcasecmp(v->name, "ss7_use_echocontrol")) {
+ struct dahdi_ss7 *link;
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (ast_true(v->value)) {
+ link->ss7.flags |= LINKSET_FLAG_USEECHOCONTROL;
+ } else {
+ link->ss7.flags &= ~LINKSET_FLAG_USEECHOCONTROL;
+ }
+ } else if (!strcasecmp(v->name, "ss7_default_echocontrol")) {
+ struct dahdi_ss7 *link;
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (ast_true(v->value)) {
+ link->ss7.flags |= LINKSET_FLAG_DEFAULTECHOCONTROL;
+ } else {
+ link->ss7.flags &= ~LINKSET_FLAG_DEFAULTECHOCONTROL;
+ }
+ } else if (!strncasecmp(v->name, "isup_timer.", 11)) {
+ struct dahdi_ss7 *link;
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (!link->ss7.ss7) {
+ ast_log(LOG_ERROR, "Please specify isup timers after sigchan!\n");
+ } else if (!ss7_set_isup_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
+ ast_log(LOG_ERROR, "Invalid isup timer %s\n", v->name);
+ }
+ } else if (!strncasecmp(v->name, "mtp3_timer.", 11)) {
+ struct dahdi_ss7 *link;
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (!link->ss7.ss7) {
+ ast_log(LOG_ERROR, "Please specify mtp3 timers after sigchan!\n");
+ } else if (!ss7_set_mtp3_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
+ ast_log(LOG_ERROR, "Invalid mtp3 timer %s\n", v->name);
+ }
+ } else if (!strcasecmp(v->name, "inr_if_no_calling")) {
+ struct dahdi_ss7 *link;
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (!link->ss7.ss7) {
+ ast_log(LOG_ERROR, "Please specify inr_if_no_calling after sigchan!\n");
+ } else if (ast_true(v->value)) {
+ ss7_set_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
+ } else {
+ ss7_clear_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
+ }
+ } else if (!strcasecmp(v->name, "non_isdn_access")) {
+ struct dahdi_ss7 *link;
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (!link->ss7.ss7) {
+ ast_log(LOG_ERROR, "Please specify non_isdn_access after sigchan!\n");
+ } else if (ast_true(v->value)) {
+ ss7_clear_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
+ } else {
+ ss7_set_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
+ }
+ } else if (!strcasecmp(v->name, "sls_shift")) {
+ struct dahdi_ss7 *link;
+ int sls_shift = atoi(v->value);
+
+ if (sls_shift < 0 || sls_shift > 7) {
+ ast_log(LOG_ERROR, "Invalid sls_shift value. Must be between 0 and 7\n");
+ return -1;
+ }
+
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (!link->ss7.ss7) {
+ ast_log(LOG_ERROR, "Please specify sls_shift after sigchan!\n");
+ } else {
+ ss7_set_sls_shift(link->ss7.ss7, sls_shift);
+ }
+ } else if (!strcasecmp(v->name, "cause_location")) {
+ struct dahdi_ss7 *link;
+ int cause_location = atoi(v->value);
+
+ if (cause_location < 0 || cause_location > 15) {
+ ast_log(LOG_ERROR, "Invalid cause_location value. Must be between 0 and 15\n");
+ return -1;
+ }
+ link = ss7_resolve_linkset(cur_linkset);
+ if (!link) {
+ ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
+ return -1;
+ }
+ if (!link->ss7.ss7) {
+ ast_log(LOG_ERROR, "Please specify cause_location after sigchan!\n");
+ } else {
+ ss7_set_cause_location(link->ss7.ss7, cause_location);
+ }
#endif /* defined(HAVE_SS7) */
#ifdef HAVE_OPENR2
} else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
@@ -17881,12 +18495,12 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
confp->mfcr2.call_files = ast_true(v->value) ? 1 : 0;
} else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
confp->mfcr2.max_ani = atoi(v->value);
- if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION){
+ if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION) {
confp->mfcr2.max_ani = AST_MAX_EXTENSION - 1;
}
} else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
confp->mfcr2.max_dnis = atoi(v->value);
- if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION){
+ if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION) {
confp->mfcr2.max_dnis = AST_MAX_EXTENSION - 1;
}
} else if (!strcasecmp(v->name, "mfcr2_category")) {
@@ -18677,6 +19291,9 @@ static int load_module(void)
}
ss7_set_error(dahdi_ss7_error);
ss7_set_message(dahdi_ss7_message);
+ ss7_set_hangup(sig_ss7_cb_hangup);
+ ss7_set_notinservice(sig_ss7_cb_notinservice);
+ ss7_set_call_null(sig_ss7_cb_call_null);
#endif /* defined(HAVE_SS7) */
res = setup_dahdi(0);
/* Make sure we can register our DAHDI channel type */
diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h
index d302bd7f7..e4a689a1a 100644
--- a/channels/chan_dahdi.h
+++ b/channels/chan_dahdi.h
@@ -389,19 +389,27 @@ struct dahdi_pvt {
unsigned int mwisendactive:1;
/*!
* \brief TRUE if channel is out of reset and ready
- * \note Set but not used.
+ * \note Used by SS7. Otherwise set but not used.
*/
unsigned int inservice:1;
/*!
- * \brief TRUE if the channel is locally blocked.
+ * \brief Bitmask for the channel being locally blocked.
* \note Applies to SS7 and MFCR2 channels.
+ * \note For MFCR2 only the first bit is used - TRUE if blocked
+ * \note For SS7 two bits are used
+ * \note Bit 0 - TRUE if maintenance blocked
+ * \note Bit 1 - TRUE if hardware blocked
*/
- unsigned int locallyblocked:1;
+ unsigned int locallyblocked:2;
/*!
- * \brief TRUE if the channel is remotely blocked.
+ * \brief Bitmask for the channel being remotely blocked. 1 maintenance, 2 blocked in hardware.
* \note Applies to SS7 and MFCR2 channels.
+ * \note For MFCR2 only the first bit is used - TRUE if blocked
+ * \note For SS7 two bits are used
+ * \note Bit 0 - TRUE if maintenance blocked
+ * \note Bit 1 - TRUE if hardware blocked
*/
- unsigned int remotelyblocked:1;
+ unsigned int remotelyblocked:2;
/*!
* \brief TRUE if the channel alarms will be managed also as Span ones
* \note Applies to all channels
diff --git a/channels/sig_ss7.c b/channels/sig_ss7.c
index 2e3918912..a7df9e9e0 100644
--- a/channels/sig_ss7.c
+++ b/channels/sig_ss7.c
@@ -41,11 +41,14 @@
#include "asterisk/causes.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
+#include "asterisk/callerid.h"
#include "asterisk/transcap.h"
#include "asterisk/stasis_channels.h"
#include "sig_ss7.h"
-#if defined(LIBSS7_ABI_COMPATIBILITY)
+#if !defined(LIBSS7_ABI_COMPATIBILITY)
+#error "Upgrade your libss7"
+#elif LIBSS7_ABI_COMPATIBILITY != 2
#error "Your installed libss7 is not compatible"
#endif
@@ -68,8 +71,6 @@ static const char *sig_ss7_call_level2str(enum sig_ss7_call_level level)
return "Alerting";
case SIG_SS7_CALL_LEVEL_CONNECT:
return "Connect";
- case SIG_SS7_CALL_LEVEL_GLARE:
- return "Glare";
}
return "Unknown";
}
@@ -132,24 +133,35 @@ static void sig_ss7_set_outgoing(struct sig_ss7_chan *p, int is_outgoing)
static void sig_ss7_set_inservice(struct sig_ss7_chan *p, int is_inservice)
{
+ p->inservice = is_inservice;
if (sig_ss7_callbacks.set_inservice) {
sig_ss7_callbacks.set_inservice(p->chan_pvt, is_inservice);
}
}
-static void sig_ss7_set_locallyblocked(struct sig_ss7_chan *p, int is_blocked)
+static void sig_ss7_set_locallyblocked(struct sig_ss7_chan *p, int is_blocked, int type)
{
- p->locallyblocked = is_blocked;
+ if (is_blocked) {
+ p->locallyblocked |= type;
+ } else {
+ p->locallyblocked &= ~type;
+ }
+
if (sig_ss7_callbacks.set_locallyblocked) {
- sig_ss7_callbacks.set_locallyblocked(p->chan_pvt, is_blocked);
+ sig_ss7_callbacks.set_locallyblocked(p->chan_pvt, p->locallyblocked);
}
}
-static void sig_ss7_set_remotelyblocked(struct sig_ss7_chan *p, int is_blocked)
+static void sig_ss7_set_remotelyblocked(struct sig_ss7_chan *p, int is_blocked, int type)
{
- p->remotelyblocked = is_blocked;
+ if (is_blocked) {
+ p->remotelyblocked |= type;
+ } else {
+ p->remotelyblocked &= ~type;
+ }
+
if (sig_ss7_callbacks.set_remotelyblocked) {
- sig_ss7_callbacks.set_remotelyblocked(p->chan_pvt, is_blocked);
+ sig_ss7_callbacks.set_remotelyblocked(p->chan_pvt, p->remotelyblocked);
}
}
@@ -277,7 +289,13 @@ static struct ast_channel *sig_ss7_new_ast_channel(struct sig_ss7_chan *p, int s
if (!p->owner) {
p->owner = ast;
}
- p->alreadyhungup = 0;
+
+ if (p->outgoing) {
+ p->do_hangup = SS7_HANGUP_FREE_CALL;
+ } else {
+ p->do_hangup = SS7_HANGUP_SEND_REL;
+ }
+
ast_channel_transfercapability_set(ast, transfercapability);
pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY",
ast_transfercapability2str(transfercapability));
@@ -295,6 +313,14 @@ static void sig_ss7_handle_link_exception(struct sig_ss7_linkset *linkset, int w
}
}
+static struct sig_ss7_linkset *sig_ss7_find_linkset(struct ss7 *ss7)
+{
+ if (sig_ss7_callbacks.find_linkset) {
+ return sig_ss7_callbacks.find_linkset(ss7);
+ }
+ return NULL;
+}
+
/*!
* \internal
* \brief Determine if a private channel structure is available.
@@ -305,7 +331,7 @@ static void sig_ss7_handle_link_exception(struct sig_ss7_linkset *linkset, int w
*/
static int sig_ss7_is_chan_available(struct sig_ss7_chan *pvt)
{
- if (!pvt->inalarm && !pvt->owner && !pvt->ss7call
+ if (pvt->inservice && !pvt->inalarm && !pvt->owner && !pvt->ss7call
&& pvt->call_level == SIG_SS7_CALL_LEVEL_IDLE
&& !pvt->locallyblocked && !pvt->remotelyblocked) {
return 1;
@@ -398,7 +424,7 @@ static void sig_ss7_queue_control(struct sig_ss7_linkset *ss7, int chanpos, int
/*!
* \internal
* \brief Queue a PVT_CAUSE_CODE frame onto the owner channel.
- * \since 11
+ * \since 11.0
*
* \param owner Owner channel of the pvt.
* \param cause String describing the cause to be placed into the frame.
@@ -425,7 +451,6 @@ static void ss7_queue_pvt_cause_data(struct ast_channel *owner, const char *caus
/*!
- * \internal
* \brief Find the channel position by CIC/DPC.
*
* \param linkset SS7 linkset control structure.
@@ -435,7 +460,7 @@ static void ss7_queue_pvt_cause_data(struct ast_channel *owner, const char *caus
* \retval chanpos on success.
* \retval -1 on error.
*/
-static int ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
+int sig_ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
{
int i;
int winner = -1;
@@ -464,45 +489,206 @@ static int ss7_find_cic_gripe(struct sig_ss7_linkset *linkset, int cic, unsigned
{
int chanpos;
- chanpos = ss7_find_cic(linkset, cic, dpc);
+ chanpos = sig_ss7_find_cic(linkset, cic, dpc);
if (chanpos < 0) {
- ast_log(LOG_WARNING, "Linkset %d: SS7 %s requested unconfigured CIC/DPC %d/%d.\n",
+ ast_log(LOG_WARNING, "Linkset %d: SS7 %s requested on unconfigured CIC/DPC %d/%d.\n",
linkset->span, msg_name, cic, dpc);
return -1;
}
return chanpos;
}
-static void ss7_handle_cqm(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
+static struct sig_ss7_chan *ss7_find_pvt(struct ss7 *ss7, int cic, unsigned int dpc)
+{
+ int chanpos;
+ struct sig_ss7_linkset *winner;
+
+ winner = sig_ss7_find_linkset(ss7);
+ if (winner && (chanpos = sig_ss7_find_cic(winner, cic, dpc)) > -1) {
+ return winner->pvts[chanpos];
+ }
+ return NULL;
+}
+
+int sig_ss7_cb_hangup(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup)
+{
+ struct sig_ss7_chan *p;
+ int res;
+
+ if (!(p = ss7_find_pvt(ss7, cic, dpc))) {
+ return SS7_CIC_NOT_EXISTS;
+ }
+
+ sig_ss7_lock_private(p);
+ if (p->owner) {
+ ast_channel_hangupcause_set(p->owner, cause);
+ ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV);
+ p->do_hangup = do_hangup;
+ res = SS7_CIC_USED;
+ } else {
+ res = SS7_CIC_IDLE;
+ }
+ sig_ss7_unlock_private(p);
+
+ return res;
+}
+
+void sig_ss7_cb_call_null(struct ss7 *ss7, struct isup_call *call, int lock)
+{
+ int i;
+ struct sig_ss7_linkset *winner;
+
+ winner = sig_ss7_find_linkset(ss7);
+ if (!winner) {
+ return;
+ }
+ for (i = 0; i < winner->numchans; i++) {
+ if (winner->pvts[i] && (winner->pvts[i]->ss7call == call)) {
+ if (lock) {
+ sig_ss7_lock_private(winner->pvts[i]);
+ }
+ winner->pvts[i]->ss7call = NULL;
+ if (winner->pvts[i]->owner) {
+ ast_channel_hangupcause_set(winner->pvts[i]->owner, AST_CAUSE_NORMAL_TEMPORARY_FAILURE);
+ ast_channel_softhangup_internal_flag_add(winner->pvts[i]->owner, AST_SOFTHANGUP_DEV);
+ }
+ if (lock) {
+ sig_ss7_unlock_private(winner->pvts[i]);
+ }
+ ast_log(LOG_WARNING, "libss7 asked set ss7 call to NULL on CIC %d DPC %d\n", winner->pvts[i]->cic, winner->pvts[i]->dpc);
+ }
+ }
+}
+
+void sig_ss7_cb_notinservice(struct ss7 *ss7, int cic, unsigned int dpc)
+{
+ struct sig_ss7_chan *p;
+
+ if (!(p = ss7_find_pvt(ss7, cic, dpc))) {
+ return;
+ }
+
+ sig_ss7_lock_private(p);
+ sig_ss7_set_inservice(p, 0);
+ sig_ss7_unlock_private(p);
+}
+
+/*!
+ * \internal
+ * \brief Check if CICs in a range belong to the linkset for a given DPC.
+ * \since 11.0
+ *
+ * \param linkset SS7 linkset control structure.
+ * \param startcic Circuit Identification Code to start from
+ * \param endcic Circuit Identification Code to search up-to
+ * \param dpc Destination Point Code
+ * \param state Array containing the status of the search
+ *
+ * \retval Nothing.
+ */
+static void ss7_check_range(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc, unsigned char *state)
+{
+ int cic;
+
+ for (cic = startcic; cic <= endcic; cic++) {
+ if (state[cic - startcic] && sig_ss7_find_cic(linkset, cic, dpc) == -1) {
+ state[cic - startcic] = 0;
+ }
+ }
+}
+
+static int ss7_match_range(struct sig_ss7_chan *pvt, int startcic, int endcic, unsigned int dpc)
+{
+ if (pvt && pvt->dpc == dpc && pvt->cic >= startcic && pvt->cic <= endcic) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Check if a range is defined for the given DPC.
+ * \since 11.0
+ *
+ * \param linkset SS7 linkset control structure.
+ * \param startcic Start CIC of the range to clear.
+ * \param endcic End CIC of the range to clear.
+ * \param dpc Destination Point Code.
+ *
+ * \note Assumes the linkset->lock is already obtained.
+ *
+ * \return TRUE if all CICs in the range are present
+ */
+int sig_ss7_find_cic_range(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
+{
+ int i, found = 0;
+
+ for (i = 0; i < linkset->numchans; i++) {
+ if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
+ found++;
+ }
+ }
+
+ if (found == endcic - startcic + 1) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static void ss7_handle_cqm(struct sig_ss7_linkset *linkset, ss7_event *e)
{
unsigned char status[32];
struct sig_ss7_chan *p = NULL;
- int i, offset;
+ int i;
+ int offset;
+ int chanpos;
+ memset(status, 0, sizeof(status));
for (i = 0; i < linkset->numchans; i++) {
- if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
+ if (ss7_match_range(linkset->pvts[i], e->cqm.startcic, e->cqm.endcic, e->cqm.opc)) {
p = linkset->pvts[i];
- offset = p->cic - startcic;
+ sig_ss7_lock_private(p);
+ offset = p->cic - e->cqm.startcic;
status[offset] = 0;
- if (p->locallyblocked)
+ if (p->locallyblocked) {
status[offset] |= (1 << 0) | (1 << 4);
- if (p->remotelyblocked)
+ }
+ if (p->remotelyblocked) {
status[offset] |= (1 << 1) | (1 << 5);
+ }
if (p->ss7call) {
- if (p->outgoing)
+ if (p->outgoing) {
status[offset] |= (1 << 3);
- else
+ } else {
status[offset] |= (1 << 2);
- } else
+ }
+ } else {
status[offset] |= 0x3 << 2;
+ }
+ sig_ss7_unlock_private(p);
}
}
- if (p)
- isup_cqr(linkset->ss7, startcic, endcic, dpc, status);
- else
+ if (p) {
+ isup_cqr(linkset->ss7, e->cqm.startcic, e->cqm.endcic, e->cqm.opc, status);
+ } else {
ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
+ }
+ chanpos = sig_ss7_find_cic(linkset, e->cqm.startcic, e->cqm.opc);
+ if (chanpos < 0) {
+ isup_free_call(linkset->ss7, e->cqm.call);
+ return;
+ }
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ p->ss7call = e->cqm.call;
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(linkset->ss7, e->cqm.call);
+ }
+ sig_ss7_unlock_private(p);
}
static inline void ss7_hangup_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
@@ -510,7 +696,7 @@ static inline void ss7_hangup_cics(struct sig_ss7_linkset *linkset, int startcic
int i;
for (i = 0; i < linkset->numchans; i++) {
- if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
+ if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
sig_ss7_lock_private(linkset->pvts[i]);
sig_ss7_lock_owner(linkset, i);
if (linkset->pvts[i]->owner) {
@@ -522,67 +708,274 @@ static inline void ss7_hangup_cics(struct sig_ss7_linkset *linkset, int startcic
}
}
-static inline void ss7_block_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block)
+/*!
+ * \param linkset SS7 linkset control structure.
+ * \param startcic Start CIC of the range to clear.
+ * \param endcic End CIC of the range to clear.
+ * \param dpc Destination Point Code.
+ * \param state Affected CICs from the operation. NULL for all CICs in the range.
+ * \param block Operation to perform. TRUE to block.
+ * \param remotely Direction of the blocking. TRUE to block/unblock remotely.
+ * \param type Blocking type - hardware or maintenance.
+ *
+ * \note Assumes the linkset->lock is already obtained.
+ * \note Must be called without sig_ss7_lock_private() obtained.
+ *
+ * \return Nothing.
+ */
+static inline void ss7_block_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block, int remotely, int type)
{
int i;
- /* XXX the use of state here seems questionable about matching up with the linkset channels */
for (i = 0; i < linkset->numchans; i++) {
- if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
+ if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
+ sig_ss7_lock_private(linkset->pvts[i]);
if (state) {
- if (state[i])
- sig_ss7_set_remotelyblocked(linkset->pvts[i], block);
- } else
- sig_ss7_set_remotelyblocked(linkset->pvts[i], block);
+ if (state[linkset->pvts[i]->cic - startcic]) {
+
+ if (remotely) {
+ sig_ss7_set_remotelyblocked(linkset->pvts[i], block, type);
+ } else {
+ sig_ss7_set_locallyblocked(linkset->pvts[i], block, type);
+ }
+
+ sig_ss7_lock_owner(linkset, i);
+ if (linkset->pvts[i]->owner) {
+ if (ast_channel_state(linkset->pvts[i]->owner) == AST_STATE_DIALING
+ && linkset->pvts[i]->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
+ ast_channel_hangupcause_set(linkset->pvts[i]->owner, SS7_CAUSE_TRY_AGAIN);
+ }
+ ast_channel_unlock(linkset->pvts[i]->owner);
+ }
+ }
+ } else {
+ if (remotely) {
+ sig_ss7_set_remotelyblocked(linkset->pvts[i], block, type);
+ } else {
+ sig_ss7_set_locallyblocked(linkset->pvts[i], block, type);
+ }
+ }
+ sig_ss7_unlock_private(linkset->pvts[i]);
}
}
}
+/*!
+ * \param linkset SS7 linkset control structure.
+ * \param startcic Start CIC of the range to set in service.
+ * \param endcic End CIC of the range to set in service.
+ * \param dpc Destination Point Code.
+ *
+ * \note Must be called without sig_ss7_lock_private() obtained.
+ *
+ * \return Nothing.
+ */
static void ss7_inservice(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
{
int i;
for (i = 0; i < linkset->numchans; i++) {
- if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))))
+ if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
+ sig_ss7_lock_private(linkset->pvts[i]);
sig_ss7_set_inservice(linkset->pvts[i], 1);
+ sig_ss7_unlock_private(linkset->pvts[i]);
+ }
}
}
+static int ss7_find_alloc_call(struct sig_ss7_chan *p)
+{
+ if (!p) {
+ return 0;
+ }
+
+ if (!p->ss7call) {
+ p->ss7call = isup_new_call(p->ss7->ss7, p->cic, p->dpc, 0);
+ if (!p->ss7call) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * XXX This routine is not tolerant of holes in the pvts[] array.
+ * XXX This routine assumes the cic's in the pvts[] array are sorted.
+ *
+ * Probably the easiest way to deal with the invalid assumptions
+ * is to have a local pvts[] array and sort it by dpc and cic.
+ * Then the existing algorithm could work.
+ */
static void ss7_reset_linkset(struct sig_ss7_linkset *linkset)
{
- int i, startcic = -1, endcic, dpc;
+ int i, startcic, endcic, dpc;
+ struct sig_ss7_chan *p;
- if (linkset->numchans <= 0)
+ if (linkset->numchans <= 0) {
return;
+ }
startcic = linkset->pvts[0]->cic;
+ p = linkset->pvts[0];
/* DB: CIC's DPC fix */
dpc = linkset->pvts[0]->dpc;
for (i = 0; i < linkset->numchans; i++) {
- if (linkset->pvts[i+1] && linkset->pvts[i+1]->dpc == dpc && ((linkset->pvts[i+1]->cic - linkset->pvts[i]->cic) == 1) && (linkset->pvts[i]->cic - startcic < 31)) {
+ if (linkset->pvts[i+1]
+ && linkset->pvts[i+1]->dpc == dpc
+ && linkset->pvts[i+1]->cic - linkset->pvts[i]->cic == 1
+ && linkset->pvts[i]->cic - startcic < (linkset->type == SS7_ANSI ? 24 : 31)) {
continue;
} else {
endcic = linkset->pvts[i]->cic;
- ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
- isup_grs(linkset->ss7, startcic, endcic, dpc);
+ ast_verb(1, "Resetting CICs %d to %d\n", startcic, endcic);
+
+ sig_ss7_lock_private(p);
+ if (!ss7_find_alloc_call(p)) {
+ ast_log(LOG_ERROR, "Unable to allocate new ss7call\n");
+ } else if (!(endcic - startcic)) { /* GRS range can not be 0 - use RSC instead */
+ isup_rsc(linkset->ss7, p->ss7call);
+ } else {
+ isup_grs(linkset->ss7, p->ss7call, endcic);
+ }
+ sig_ss7_unlock_private(p);
/* DB: CIC's DPC fix */
if (linkset->pvts[i+1]) {
startcic = linkset->pvts[i+1]->cic;
dpc = linkset->pvts[i+1]->dpc;
+ p = linkset->pvts[i+1];
}
}
}
}
-/* This function is assumed to be called with the private channel lock and linkset lock held */
+/*!
+ * \internal
+ * \brief Complete the RSC procedure started earlier
+ * \since 11.0
+ *
+ * \param p Signaling private structure pointer.
+ *
+ * \note Assumes the ss7->lock is already obtained.
+ * \note Assumes sig_ss7_lock_private(p) is already obtained.
+ *
+ * \return Nothing.
+ */
+static void ss7_do_rsc(struct sig_ss7_chan *p)
+{
+ if (!p || !p->ss7call) {
+ return;
+ }
+
+ isup_rsc(p->ss7->ss7, p->ss7call);
+
+ if (p->locallyblocked & SS7_BLOCKED_MAINTENANCE) {
+ isup_blo(p->ss7->ss7, p->ss7call);
+ } else {
+ sig_ss7_set_locallyblocked(p, 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Start RSC procedure on a specific link
+ * \since 11.0
+ *
+ * \param ss7 SS7 linkset control structure.
+ * \param which Channel position in the span.
+ *
+ * \note Assumes the ss7->lock is already obtained.
+ * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
+ *
+ * \return TRUE on success
+ */
+static int ss7_start_rsc(struct sig_ss7_linkset *linkset, int which)
+{
+ if (!linkset->pvts[which]) {
+ return 0;
+ }
+
+ if (!ss7_find_alloc_call(linkset->pvts[which])) {
+ return 0;
+ }
+
+ sig_ss7_set_remotelyblocked(linkset->pvts[which], 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
+ sig_ss7_set_inservice(linkset->pvts[which], 0);
+ sig_ss7_loopback(linkset->pvts[which], 0);
+
+ sig_ss7_lock_owner(linkset, which);
+ if (linkset->pvts[which]->owner) {
+ ast_channel_hangupcause_set(linkset->pvts[which]->owner, AST_CAUSE_NORMAL_CLEARING);
+ ast_softhangup_nolock(linkset->pvts[which]->owner, AST_SOFTHANGUP_DEV);
+ ast_channel_unlock(linkset->pvts[which]->owner);
+ linkset->pvts[which]->do_hangup = SS7_HANGUP_SEND_RSC;
+ } else {
+ ss7_do_rsc(linkset->pvts[which]);
+ }
+
+ return 1;
+}
+
+/*!
+ * \internal
+ * \brief Determine if a private channel structure is available.
+ * \since 11.0
+ *
+ * \param linkset SS7 linkset control structure.
+ * \param startcic Start CIC of the range to clear.
+ * \param endcic End CIC of the range to clear.
+ * \param dpc Destination Point Code.
+ * \param do_hangup What we have to do to clear the call.
+ *
+ * \note Assumes the linkset->lock is already obtained.
+ * \note Must be called without sig_ss7_lock_private() obtained.
+ *
+ * \return Nothing.
+ */
+static void ss7_clear_channels(struct sig_ss7_linkset *linkset, int startcic, int endcic, int dpc, int do_hangup)
+{
+ int i;
+
+ for (i = 0; i < linkset->numchans; i++) {
+ if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
+ sig_ss7_lock_private(linkset->pvts[i]);
+ sig_ss7_set_inservice(linkset->pvts[i], 0);
+ sig_ss7_lock_owner(linkset, i);
+ if (linkset->pvts[i]->owner) {
+ ast_channel_hangupcause_set(linkset->pvts[i]->owner,
+ AST_CAUSE_NORMAL_CLEARING);
+ ast_softhangup_nolock(linkset->pvts[i]->owner, AST_SOFTHANGUP_DEV);
+ ast_channel_unlock(linkset->pvts[i]->owner);
+ linkset->pvts[i]->do_hangup = (linkset->pvts[i]->cic != startcic) ?
+ do_hangup : SS7_HANGUP_DO_NOTHING;
+ } else if (linkset->pvts[i] && linkset->pvts[i]->cic != startcic) {
+ isup_free_call(linkset->pvts[i]->ss7->ss7, linkset->pvts[i]->ss7call);
+ linkset->pvts[i]->ss7call = NULL;
+ }
+ sig_ss7_unlock_private(linkset->pvts[i]);
+ }
+ }
+}
+
+/*!
+ * \internal
+ *
+ * \param p Signaling private structure pointer.
+ * \param linkset SS7 linkset control structure.
+ *
+ * \note Assumes the linkset->lock is already obtained.
+ * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing.
+ */
static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *linkset)
{
struct ss7 *ss7 = linkset->ss7;
int law;
struct ast_channel *c;
char tmp[256];
+ char *strp;
struct ast_callid *callid = NULL;
int callid_created = ast_callid_threadstorage_auto(&callid);
@@ -600,6 +993,8 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
law = SIG_SS7_ULAW;
}
+ isup_set_echocontrol(p->ss7call, (linkset->flags & LINKSET_FLAG_DEFAULTECHOCONTROL) ? 1 : 0);
+
/*
* Release the SS7 lock while we create the channel so other
* threads can send messages. We must also release the private
@@ -614,7 +1009,6 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
sig_ss7_lock_private(p);
isup_rel(linkset->ss7, p->ss7call, AST_CAUSE_SWITCH_CONGESTION);
p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
- p->alreadyhungup = 1;
ast_callid_threadstorage_auto_clean(callid, callid_created);
return;
}
@@ -623,8 +1017,6 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
ast_channel_lock(c);
sig_ss7_lock_private(p);
- sig_ss7_set_echocanceller(p, 1);
-
ast_channel_stage_snapshot(c);
/*
@@ -658,11 +1050,6 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
/* Clear this after we set it */
p->gen_dig_number[0] = 0;
}
- if (!ast_strlen_zero(p->orig_called_num)) {
- pbx_builtin_setvar_helper(c, "SS7_ORIG_CALLED_NUM", p->orig_called_num);
- /* Clear this after we set it */
- p->orig_called_num[0] = 0;
- }
snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_type);
pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGTYPE", tmp);
@@ -695,15 +1082,174 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
/* Clear this after we set it */
p->calling_party_cat = 0;
- if (!ast_strlen_zero(p->redirecting_num)) {
- pbx_builtin_setvar_helper(c, "SS7_REDIRECTING_NUMBER", p->redirecting_num);
+ if (p->redirect_counter) {
+ struct ast_party_redirecting redirecting;
+
+ switch (p->redirect_info_ind) {
+ case 0:
+ strp = "NO_REDIRECTION";
+ break;
+ case 1:
+ strp = "CALL_REROUTED_PRES_ALLOWED";
+ break;
+ case 2:
+ strp = "CALL_REROUTED_INFO_RESTRICTED";
+ break;
+ case 3:
+ strp = "CALL_DIVERTED_PRES_ALLOWED";
+ break;
+ case 4:
+ strp = "CALL_DIVERTED_INFO_RESTRICTED";
+ break;
+ case 5:
+ strp = "CALL_REROUTED_PRES_RESTRICTED";
+ break;
+ case 6:
+ strp = "CALL_DIVERTED_PRES_RESTRICTED";
+ break;
+ case 7:
+ strp = "SPARE";
+ break;
+ default:
+ strp = "NO_REDIRECTION";
+ break;
+ }
+ pbx_builtin_setvar_helper(c, "SS7_REDIRECT_INFO_IND", strp);
/* Clear this after we set it */
- p->redirecting_num[0] = 0;
- }
- if (!ast_strlen_zero(p->generic_name)) {
- pbx_builtin_setvar_helper(c, "SS7_GENERIC_NAME", p->generic_name);
+ p->redirect_info_ind = 0;
+
+ ast_party_redirecting_init(&redirecting);
+
+ if (p->redirect_info_counter) {
+ redirecting.count = p->redirect_info_counter;
+ if (p->redirect_info_counter != p->redirect_counter) {
+ if (p->redirect_info_counter < p->redirect_counter) {
+ redirecting.count = p->redirect_counter;
+ }
+ ast_log(LOG_WARNING, "Redirect counters differ: %u while info says %u - using %u\n",
+ p->redirect_counter, p->redirect_info_counter, redirecting.count);
+ }
+ /* Clear this after we set it */
+ p->redirect_info_counter = 0;
+ p->redirect_counter = 0;
+ }
+
+ if (p->redirect_counter) {
+ redirecting.count = p->redirect_counter;
+ /* Clear this after we set it */
+ p->redirect_counter = 0;
+ }
+
+ switch (p->redirect_info_orig_reas) {
+ case SS7_REDIRECTING_REASON_UNKNOWN:
+ redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN;
+ break;
+ case SS7_REDIRECTING_REASON_USER_BUSY:
+ redirecting.orig_reason.code = AST_REDIRECTING_REASON_USER_BUSY;
+ break;
+ case SS7_REDIRECTING_REASON_NO_ANSWER:
+ redirecting.orig_reason.code = AST_REDIRECTING_REASON_NO_ANSWER;
+ break;
+ case SS7_REDIRECTING_REASON_UNCONDITIONAL:
+ redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNCONDITIONAL;
+ break;
+ default:
+ redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN;
+ break;
+ }
+
+ switch (p->redirect_info_reas) {
+ case SS7_REDIRECTING_REASON_UNKNOWN:
+ redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
+ break;
+ case SS7_REDIRECTING_REASON_USER_BUSY:
+ redirecting.reason.code = AST_REDIRECTING_REASON_USER_BUSY;
+ if (!p->redirect_info_orig_reas && redirecting.count == 1) {
+ redirecting.orig_reason.code = AST_REDIRECTING_REASON_USER_BUSY;
+ }
+ break;
+ case SS7_REDIRECTING_REASON_NO_ANSWER:
+ redirecting.reason.code = AST_REDIRECTING_REASON_NO_ANSWER;
+ if (!p->redirect_info_orig_reas && redirecting.count == 1) {
+ redirecting.orig_reason.code = AST_REDIRECTING_REASON_NO_ANSWER;
+ }
+ break;
+ case SS7_REDIRECTING_REASON_UNCONDITIONAL:
+ redirecting.reason.code = AST_REDIRECTING_REASON_UNCONDITIONAL;
+ if (!p->redirect_info_orig_reas && redirecting.count == 1) {
+ redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNCONDITIONAL;
+ }
+ break;
+ case SS7_REDIRECTING_REASON_DEFLECTION_DURING_ALERTING:
+ case SS7_REDIRECTING_REASON_DEFLECTION_IMMEDIATE_RESPONSE:
+ redirecting.reason.code = AST_REDIRECTING_REASON_DEFLECTION;
+ break;
+ case SS7_REDIRECTING_REASON_UNAVAILABLE:
+ redirecting.reason.code = AST_REDIRECTING_REASON_UNAVAILABLE;
+ break;
+ default:
+ redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
+ break;
+ }
/* Clear this after we set it */
- p->generic_name[0] = 0;
+ p->redirect_info_orig_reas = 0;
+ p->redirect_info_reas = 0;
+
+ if (!ast_strlen_zero(p->redirecting_num)) {
+ redirecting.from.number.str = ast_strdup(p->redirecting_num);
+ redirecting.from.number.presentation = p->redirecting_presentation;
+ redirecting.from.number.valid = 1;
+ /* Clear this after we set it */
+ p->redirecting_num[0] = 0;
+ }
+
+ if (!ast_strlen_zero(p->generic_name)) {
+ redirecting.from.name.str = ast_strdup(p->generic_name);
+ redirecting.from.name.presentation = p->redirecting_presentation;
+ redirecting.from.name.valid = 1;
+ /* Clear this after we set it */
+ p->generic_name[0] = 0;
+ }
+
+ if (!ast_strlen_zero(p->orig_called_num)) {
+ redirecting.orig.number.str = ast_strdup(p->orig_called_num);
+ redirecting.orig.number.presentation = p->orig_called_presentation;
+ redirecting.orig.number.valid = 1;
+ /* Clear this after we set it */
+ p->orig_called_num[0] = 0;
+ } else if (redirecting.count == 1) {
+ ast_party_id_copy(&redirecting.orig, &redirecting.from);
+ }
+
+ ast_channel_update_redirecting(c, &redirecting, NULL);
+ ast_party_redirecting_free(&redirecting);
+ }
+
+ if (p->cug_indicator != ISUP_CUG_NON) {
+ sprintf(tmp, "%d", p->cug_interlock_code);
+ pbx_builtin_setvar_helper(c, "SS7_CUG_INTERLOCK_CODE", tmp);
+
+ switch (p->cug_indicator) {
+ case ISUP_CUG_NON:
+ strp = "NON_CUG";
+ break;
+ case ISUP_CUG_OUTGOING_ALLOWED:
+ strp = "OUTGOING_ALLOWED";
+ break;
+ case ISUP_CUG_OUTGOING_NOT_ALLOWED:
+ strp = "OUTGOING_NOT_ALLOWED";
+ break;
+ default:
+ strp = "SPARE";
+ break;
+ }
+ pbx_builtin_setvar_helper(c, "SS7_CUG_INDICATOR", strp);
+
+ if (!ast_strlen_zero(p->cug_interlock_ni)) {
+ pbx_builtin_setvar_helper(c, "SS7_CUG_INTERLOCK_NI", p->cug_interlock_ni);
+ }
+
+ p->cug_indicator = ISUP_CUG_NON;
}
ast_channel_stage_snapshot_done(c);
@@ -745,6 +1291,9 @@ static void ss7_apply_plan_to_number(char *buf, size_t size, const struct sig_ss
case SS7_NAI_UNKNOWN:
snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
break;
+ case SS7_NAI_NETWORKROUTED:
+ snprintf(buf, size, "%s%s", ss7->networkroutedprefix, number);
+ break;
default:
snprintf(buf, size, "%s", number);
break;
@@ -786,6 +1335,50 @@ static struct ast_callid *func_ss7_linkset_callid(struct sig_ss7_linkset *linkse
return callid;
}
+/*!
+ * \internal
+ * \brief Proceed with the call based on the extension matching status
+ * is matching in the dialplan.
+ * \since 11.0
+ *
+ * \param linkset ss7 span control structure.
+ * \param p Signaling private structure pointer.
+ * \param e Event causing the match.
+ *
+ * \note Assumes the linkset->lock is already obtained.
+ * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing.
+ */
+static void ss7_match_extension(struct sig_ss7_linkset *linkset, struct sig_ss7_chan *p, ss7_event *e)
+{
+ ast_verb(3, "SS7 exten: %s complete: %d\n", p->exten, p->called_complete);
+
+ if (!p->called_complete
+ && linkset->type == SS7_ITU /* ANSI does not support overlap dialing. */
+ && ast_matchmore_extension(NULL, p->context, p->exten, 1, p->cid_num)
+ && !isup_start_digittimeout(linkset->ss7, p->ss7call)) {
+ /* Wait for more digits. */
+ return;
+ }
+ if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
+ /* DNID is complete */
+ p->called_complete = 1;
+ sig_ss7_set_dnid(p, p->exten);
+
+ /* If COT successful start call! */
+ if ((e->e == ISUP_EVENT_IAM)
+ ? !(e->iam.cot_check_required || e->iam.cot_performed_on_previous_cic)
+ : (!(e->sam.cot_check_required || e->sam.cot_performed_on_previous_cic) || e->sam.cot_check_passed)) {
+ ss7_start_call(p, linkset);
+ }
+ return;
+ }
+
+ ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
+ isup_rel(linkset->ss7, (e->e == ISUP_EVENT_IAM) ? e->iam.call : e->sam.call, AST_CAUSE_UNALLOCATED);
+}
+
/* This is a thread per linkset that handles all received events from libss7. */
void *ss7_linkset(void *data)
{
@@ -796,6 +1389,7 @@ void *ss7_linkset(void *data)
ss7_event *e = NULL;
struct sig_ss7_chan *p;
struct pollfd pollers[SIG_SS7_NUM_DCHANS];
+ unsigned char mb_state[255];
int nextms;
#define SS7_MAX_POLL 60000 /* Maximum poll time in ms. */
@@ -843,16 +1437,13 @@ void *ss7_linkset(void *data)
pthread_testcancel();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ ast_mutex_lock(&linkset->lock);
if ((res < 0) && (errno != EINTR)) {
ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
} else if (!res) {
- ast_mutex_lock(&linkset->lock);
ss7_schedule_run(ss7);
- ast_mutex_unlock(&linkset->lock);
- continue;
}
- ast_mutex_lock(&linkset->lock);
for (i = 0; i < linkset->numsigchans; i++) {
if (pollers[i].revents & POLLPRI) {
sig_ss7_handle_link_exception(linkset, i);
@@ -881,23 +1472,26 @@ void *ss7_linkset(void *data)
switch (e->e) {
case SS7_EVENT_UP:
if (linkset->state != LINKSET_STATE_UP) {
- ast_verbose("--- SS7 Up ---\n");
+ ast_verb(1, "--- SS7 Up ---\n");
ss7_reset_linkset(linkset);
}
linkset->state = LINKSET_STATE_UP;
break;
case SS7_EVENT_DOWN:
- ast_verbose("--- SS7 Down ---\n");
+ ast_verb(1, "--- SS7 Down ---\n");
linkset->state = LINKSET_STATE_DOWN;
for (i = 0; i < linkset->numchans; i++) {
p = linkset->pvts[i];
if (p) {
- sig_ss7_set_alarm(p, 1);
+ sig_ss7_set_inservice(p, 0);
+ if (linkset->flags & LINKSET_FLAG_INITIALHWBLO) {
+ sig_ss7_set_remotelyblocked(p, 1, SS7_BLOCKED_HARDWARE);
+ }
}
}
break;
case MTP2_LINK_UP:
- ast_verbose("MTP2 link up (SLC %d)\n", e->gen.data);
+ ast_verb(1, "MTP2 link up (SLC %d)\n", e->gen.data);
break;
case MTP2_LINK_DOWN:
ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
@@ -905,6 +1499,7 @@ void *ss7_linkset(void *data)
case ISUP_EVENT_CPG:
chanpos = ss7_find_cic_gripe(linkset, e->cpg.cic, e->cpg.opc, "CPG");
if (chanpos < 0) {
+ isup_free_call(ss7, e->cpg.call);
break;
}
p = linkset->pvts[chanpos];
@@ -919,6 +1514,21 @@ void *ss7_linkset(void *data)
sig_ss7_lock_owner(linkset, chanpos);
if (p->owner) {
ast_setstate(p->owner, AST_STATE_RINGING);
+ if (!ast_strlen_zero(e->cpg.connected_num)) {
+ struct ast_party_connected_line ast_connected;
+ char connected_num[AST_MAX_EXTENSION];
+
+ ast_party_connected_line_init(&ast_connected);
+ ast_connected.id.number.presentation =
+ ss7_pres_scr2cid_pres(e->cpg.connected_presentation_ind,
+ e->cpg.connected_screening_ind);
+ ss7_apply_plan_to_number(connected_num, sizeof(connected_num),
+ linkset, e->cpg.connected_num, e->cpg.connected_nai);
+ ast_connected.id.number.str = ast_strdup(connected_num);
+ ast_connected.id.number.valid = 1;
+ ast_channel_queue_connected_line_update(p->owner, &ast_connected, NULL);
+ ast_party_connected_line_free(&ast_connected);
+ }
ast_channel_unlock(p->owner);
}
sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
@@ -941,95 +1551,201 @@ void *ss7_linkset(void *data)
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_RSC:
- ast_verbose("Resetting CIC %d\n", e->rsc.cic);
+ ast_verb(1, "Resetting CIC %d\n", e->rsc.cic);
chanpos = ss7_find_cic_gripe(linkset, e->rsc.cic, e->rsc.opc, "RSC");
if (chanpos < 0) {
+ isup_free_call(ss7, e->rsc.call);
break;
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
+ p->ss7call = e->rsc.call;
callid = func_ss7_linkset_callid(linkset, chanpos);
sig_ss7_set_inservice(p, 1);
- sig_ss7_set_remotelyblocked(p, 0);
+ sig_ss7_set_remotelyblocked(p, 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
+
+ if (p->locallyblocked & SS7_BLOCKED_MAINTENANCE) {
+ isup_blo(ss7, e->rsc.call);
+ } else if (p->locallyblocked & SS7_BLOCKED_HARDWARE) {
+ sig_ss7_set_locallyblocked(p, 0, SS7_BLOCKED_HARDWARE);
+ }
+
isup_set_call_dpc(e->rsc.call, p->dpc);
sig_ss7_lock_owner(linkset, chanpos);
- p->ss7call = NULL;
if (p->owner) {
+ p->do_hangup = SS7_HANGUP_SEND_RLC;
+ if (!(e->rsc.got_sent_msg & ISUP_SENT_IAM)) {
+ /* Q.784 6.2.3 */
+ ast_channel_hangupcause_set(p->owner, AST_CAUSE_NORMAL_CLEARING);
+ } else {
+ ast_channel_hangupcause_set(p->owner, SS7_CAUSE_TRY_AGAIN);
+ }
+
ss7_queue_pvt_cause_data(p->owner, "SS7 ISUP_EVENT_RSC", AST_CAUSE_INTERWORKING);
+
ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
ast_channel_unlock(p->owner);
+ } else {
+ isup_rlc(ss7, e->rsc.call);
+ p->ss7call = isup_free_call_if_clear(ss7, e->rsc.call);
}
+ /* End the loopback if we have one */
+ sig_ss7_loopback(p, 0);
+
sig_ss7_unlock_private(p);
- isup_rlc(ss7, e->rsc.call);
break;
case ISUP_EVENT_GRS:
- ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
- chanpos = ss7_find_cic_gripe(linkset, e->grs.startcic, e->grs.opc, "GRS");
- if (chanpos < 0) {
+ if (!sig_ss7_find_cic_range(linkset, e->grs.startcic, e->grs.endcic,
+ e->grs.opc)) {
+ ast_log(LOG_WARNING, "GRS on unconfigured range CIC %d - %d PC %d\n",
+ e->grs.startcic, e->grs.endcic, e->grs.opc);
+ chanpos = sig_ss7_find_cic(linkset, e->grs.startcic, e->grs.opc);
+ if (chanpos < 0) {
+ isup_free_call(ss7, e->grs.call);
+ break;
+ }
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ p->ss7call = isup_free_call_if_clear(ss7, e->grs.call);
+ sig_ss7_unlock_private(p);
break;
}
- p = linkset->pvts[chanpos];
- isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc);
- ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0);
- ss7_hangup_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc);
+
+ /* Leave startcic last to collect all cics mb_state */
+ for (i = e->grs.endcic - e->grs.startcic; 0 <= i; --i) {
+ /*
+ * We are guaranteed to find chanpos because
+ * sig_ss7_find_cic_range() includes it.
+ */
+ chanpos = sig_ss7_find_cic(linkset, e->grs.startcic + i, e->grs.opc);
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+
+ if (p->locallyblocked & SS7_BLOCKED_MAINTENANCE) {
+ mb_state[i] = 1;
+ } else {
+ mb_state[i] = 0;
+ sig_ss7_set_locallyblocked(p, 0, SS7_BLOCKED_HARDWARE);
+ }
+
+ sig_ss7_set_remotelyblocked(p, 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
+
+ if (!i) {
+ p->ss7call = e->grs.call;
+ isup_gra(ss7, p->ss7call, e->grs.endcic, mb_state);
+ }
+
+ sig_ss7_lock_owner(linkset, chanpos);
+ if (p->owner) {
+ ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV);
+ if (ast_channel_state(p->owner) == AST_STATE_DIALING
+ && linkset->pvts[i]->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
+ ast_channel_hangupcause_set(p->owner, SS7_CAUSE_TRY_AGAIN);
+ } else {
+ ast_channel_hangupcause_set(p->owner, AST_CAUSE_NORMAL_CLEARING);
+ }
+ p->do_hangup = SS7_HANGUP_FREE_CALL;
+ ast_channel_unlock(p->owner);
+ } else if (!i) {
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
+ } else if (p->ss7call) {
+ /* clear any other session */
+ isup_free_call(ss7, p->ss7call);
+ p->ss7call = NULL;
+ }
+ sig_ss7_set_inservice(p, 1);
+ sig_ss7_unlock_private(p);
+ }
break;
case ISUP_EVENT_CQM:
- ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
- ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic, e->cqm.opc);
+ ast_debug(1, "Got Circuit group query message from CICs %d to %d\n",
+ e->cqm.startcic, e->cqm.endcic);
+ ss7_handle_cqm(linkset, e);
break;
case ISUP_EVENT_GRA:
- ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
+ if (!sig_ss7_find_cic_range(linkset, e->gra.startcic,
+ e->gra.endcic, e->gra.opc)) { /* Never will be true */
+ ast_log(LOG_WARNING, "GRA on unconfigured range CIC %d - %d PC %d\n",
+ e->gra.startcic, e->gra.endcic, e->gra.opc);
+ isup_free_call(ss7, e->gra.call);
+ break;
+ }
+ ast_verb(1, "Got reset acknowledgement from CIC %d to %d DPC: %d\n",
+ e->gra.startcic, e->gra.endcic, e->gra.opc);
+ ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc,
+ e->gra.status, 1, 1, SS7_BLOCKED_MAINTENANCE);
ss7_inservice(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc);
- ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc, e->gra.status, 1);
+
+ chanpos = sig_ss7_find_cic(linkset, e->gra.startcic, e->gra.opc);
+ if (chanpos < 0) {
+ isup_free_call(ss7, e->gra.call);
+ break;
+ }
+
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+
+ /* we may send a CBD with GRS! */
+ p->ss7call = isup_free_call_if_clear(ss7, e->gra.call);
+ sig_ss7_unlock_private(p);
break;
- case ISUP_EVENT_IAM:
- ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
- chanpos = ss7_find_cic_gripe(linkset, e->iam.cic, e->iam.opc, "IAM");
+ case ISUP_EVENT_SAM:
+ chanpos = ss7_find_cic_gripe(linkset, e->sam.cic, e->sam.opc, "SAM");
if (chanpos < 0) {
- isup_rel(ss7, e->iam.call, -1);
+ isup_free_call(ss7, e->sam.call);
break;
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
sig_ss7_lock_owner(linkset, chanpos);
- if (p->call_level != SIG_SS7_CALL_LEVEL_IDLE) {
- /*
- * Detected glare/dual-seizure
- *
- * Always abort both calls since we can't implement the dual
- * seizure procedures due to our channel assignment architecture
- * and the fact that we cannot tell libss7 to discard its call
- * structure to ignore the incoming IAM.
- */
- ast_debug(1,
- "Linkset %d: SS7 IAM glare on CIC/DPC %d/%d. Dropping both calls.\n",
- linkset->span, e->iam.cic, e->iam.opc);
- if (p->call_level == SIG_SS7_CALL_LEVEL_ALLOCATED) {
- /*
- * We have not sent our IAM yet and we never will at this point.
- */
- p->alreadyhungup = 1;
- isup_rel(ss7, e->iam.call, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
- }
- p->call_level = SIG_SS7_CALL_LEVEL_GLARE;
- if (p->owner) {
- ss7_queue_pvt_cause_data(p->owner, "SS7 ISUP_EVENT_IAM (glare)", AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
- ast_channel_hangupcause_set(p->owner, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
- ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
- ast_channel_unlock(p->owner);
- }
+ if (p->owner) {
+ ast_log(LOG_WARNING, "SAM on CIC %d PC %d already have call\n", e->sam.cic, e->sam.opc);
+ ast_channel_unlock(p->owner);
sig_ss7_unlock_private(p);
break;
}
+ p->called_complete = 0;
+ if (!ast_strlen_zero(e->sam.called_party_num)) {
+ char *st;
+ strncat(p->exten, e->sam.called_party_num, sizeof(p->exten) - strlen(p->exten) - 1);
+ st = strchr(p->exten, '#');
+ if (st) {
+ *st = '\0';
+ p->called_complete = 1;
+ }
+ ss7_match_extension(linkset, p, e);
+ }
+ sig_ss7_unlock_private(p);
+ break;
+ case ISUP_EVENT_IAM:
+ ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
+ chanpos = ss7_find_cic_gripe(linkset, e->iam.cic, e->iam.opc, "IAM");
+ if (chanpos < 0) {
+ isup_free_call(ss7, e->iam.call);
+ break;
+ }
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
/*
- * The channel should not have an owner at this point since we
+ * The channel should be idle and not have an owner at this point since we
* are in the process of creating an owner for it.
*/
- ast_assert(!p->owner);
+ ast_assert(!p->owner && p->call_level == SIG_SS7_CALL_LEVEL_IDLE);
+
+ if (p->remotelyblocked) {
+ ast_log(LOG_NOTICE, "Got IAM on remotely blocked CIC %d DPC %d remove blocking\n", e->iam.cic, e->iam.opc);
+ sig_ss7_set_remotelyblocked(p, 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
+ sig_ss7_set_inservice(p, 1);
+ }
if (!sig_ss7_is_chan_available(p)) {
/* Circuit is likely blocked or in alarm. */
isup_rel(ss7, e->iam.call, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+ if (p->locallyblocked) {
+ isup_clear_callflags(ss7, e->iam.call, ISUP_GOT_IAM);
+ p->ss7call = isup_free_call_if_clear(ss7, e->iam.call);
+ ast_log(LOG_WARNING, "Got IAM on locally blocked CIC %d DPC %d, ignore\n", e->iam.cic, e->iam.opc);
+ }
sig_ss7_unlock_private(p);
break;
}
@@ -1043,18 +1759,14 @@ void *ss7_linkset(void *data)
if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
- } else
- p->cid_num[0] = 0;
-
- /* Set DNID */
- if (!ast_strlen_zero(e->iam.called_party_num)) {
- ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset,
- e->iam.called_party_num, e->iam.called_nai);
} else {
- p->exten[0] = '\0';
+ p->cid_num[0] = 0;
+ if (e->iam.presentation_ind) {
+ p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
+ }
}
- sig_ss7_set_dnid(p, p->exten);
+ p->called_complete = 0;
if (p->immediate) {
p->exten[0] = 's';
p->exten[1] = '\0';
@@ -1064,16 +1776,18 @@ void *ss7_linkset(void *data)
st = strchr(p->exten, '#');
if (st) {
*st = '\0';
+ p->called_complete = 1;
}
} else {
p->exten[0] = '\0';
}
p->cid_ani[0] = '\0';
- if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name)))
+ if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name))) {
ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name));
- else
+ } else {
p->cid_name[0] = '\0';
+ }
p->cid_ani2 = e->iam.oli_ani2;
p->cid_ton = 0;
@@ -1087,81 +1801,162 @@ void *ss7_linkset(void *data)
p->gen_dig_type = e->iam.gen_dig_type;
p->gen_dig_scheme = e->iam.gen_dig_scheme;
ast_copy_string(p->jip_number, e->iam.jip_number, sizeof(p->jip_number));
- ast_copy_string(p->orig_called_num, e->iam.orig_called_num, sizeof(p->orig_called_num));
- ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num));
+ if (!ast_strlen_zero(e->iam.orig_called_num)) {
+ ss7_apply_plan_to_number(p->orig_called_num, sizeof(p->orig_called_num), linkset, e->iam.orig_called_num, e->iam.orig_called_nai);
+ p->orig_called_presentation = ss7_pres_scr2cid_pres(e->iam.orig_called_pres_ind, e->iam.orig_called_screening_ind);
+ }
+ if (!ast_strlen_zero(e->iam.redirecting_num)) {
+ ss7_apply_plan_to_number(p->redirecting_num, sizeof(p->redirecting_num), linkset, e->iam.redirecting_num, e->iam.redirecting_num_nai);
+ p->redirecting_presentation = ss7_pres_scr2cid_pres(e->iam.redirecting_num_presentation_ind, e->iam.redirecting_num_screening_ind);
+ }
ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name));
p->calling_party_cat = e->iam.calling_party_cat;
+ p->redirect_counter = e->iam.redirect_counter;
+ p->redirect_info = e->iam.redirect_info;
+ p->redirect_info_ind = e->iam.redirect_info_ind;
+ p->redirect_info_orig_reas = e->iam.redirect_info_orig_reas;
+ p->redirect_info_counter = e->iam.redirect_info_counter;
+ if (p->redirect_info_counter && !p->redirect_counter) {
+ p->redirect_counter = p->redirect_info_counter;
+ }
+ p->redirect_info_reas = e->iam.redirect_info_reas;
+ p->cug_indicator = e->iam.cug_indicator;
+ p->cug_interlock_code = e->iam.cug_interlock_code;
+ ast_copy_string(p->cug_interlock_ni, e->iam.cug_interlock_ni, sizeof(p->cug_interlock_ni));
+ if (e->iam.cot_check_required) {
+ sig_ss7_loopback(p, 1);
+ }
+
+ p->echocontrol_ind = e->iam.echocontrol_ind;
sig_ss7_set_caller_id(p);
+ ss7_match_extension(linkset, p, e);
+ sig_ss7_unlock_private(p);
- if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
- if (e->iam.cot_check_required) {
- p->call_level = SIG_SS7_CALL_LEVEL_CONTINUITY;
+ if (e->iam.cot_performed_on_previous_cic) {
+ chanpos = sig_ss7_find_cic(linkset, (e->iam.cic - 1), e->iam.opc);
+ if (chanpos < 0) {
+ /* some stupid switch do this */
+ ast_verb(1, "COT request on previous nonexistent CIC %d in IAM PC %d\n", (e->iam.cic - 1), e->iam.opc);
+ break;
+ }
+ ast_verb(1, "COT request on previous CIC %d in IAM PC %d\n", (e->iam.cic - 1), e->iam.opc);
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ if (sig_ss7_is_chan_available(p)) {
+ sig_ss7_set_inservice(p, 0); /* to prevent to use this circuit */
sig_ss7_loopback(p, 1);
- } else {
+ } /* If already have a call don't loop */
+ sig_ss7_unlock_private(p);
+ }
+ break;
+ case ISUP_EVENT_DIGITTIMEOUT:
+ chanpos = ss7_find_cic_gripe(linkset, e->digittimeout.cic, e->digittimeout.opc, "DIGITTIMEOUT");
+ if (chanpos < 0) {
+ isup_free_call(ss7, e->digittimeout.call);
+ break;
+ }
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ ast_debug(1, "Digittimeout on CIC: %d PC: %d\n", e->digittimeout.cic, e->digittimeout.opc);
+ if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
+ /* DNID is complete */
+ p->called_complete = 1;
+ sig_ss7_set_dnid(p, p->exten);
+
+ /* If COT successful start call! */
+ if (!(e->digittimeout.cot_check_required || e->digittimeout.cot_performed_on_previous_cic) || e->digittimeout.cot_check_passed) {
ss7_start_call(p, linkset);
}
} else {
ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
- p->alreadyhungup = 1;
- isup_rel(ss7, e->iam.call, AST_CAUSE_UNALLOCATED);
+ isup_rel(linkset->ss7, e->digittimeout.call, AST_CAUSE_UNALLOCATED);
}
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_COT:
+ if (e->cot.cot_performed_on_previous_cic) {
+ chanpos = sig_ss7_find_cic(linkset, (e->cot.cic - 1), e->cot.opc);
+ /* some stupid switches do this!!! */
+ if (-1 < chanpos) {
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ sig_ss7_set_inservice(p, 1);
+ sig_ss7_loopback(p, 0);
+ sig_ss7_unlock_private(p);;
+ ast_verb(1, "Loop turned off on CIC: %d PC: %d\n", (e->cot.cic - 1), e->cot.opc);
+ }
+ }
+
chanpos = ss7_find_cic_gripe(linkset, e->cot.cic, e->cot.opc, "COT");
if (chanpos < 0) {
- isup_rel(ss7, e->cot.call, -1);
+ isup_free_call(ss7, e->cot.call);
break;
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
+ p->ss7call = e->cot.call;
+
if (p->loopedback) {
sig_ss7_loopback(p, 0);
+ ast_verb(1, "Loop turned off on CIC: %d PC: %d\n", e->cot.cic, e->cot.opc);
+ }
+
+ /* Don't start call if we didn't get IAM or COT failed! */
+ if ((e->cot.got_sent_msg & ISUP_GOT_IAM) && e->cot.passed && p->called_complete) {
ss7_start_call(p, linkset);
}
+
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_CCR:
ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
chanpos = ss7_find_cic_gripe(linkset, e->ccr.cic, e->ccr.opc, "CCR");
if (chanpos < 0) {
+ isup_free_call(ss7, e->ccr.call);
break;
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
+ p->ss7call = e->ccr.call;
sig_ss7_loopback(p, 1);
+ if (linkset->type == SS7_ANSI) {
+ isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
+ }
sig_ss7_unlock_private(p);
-
- isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
break;
case ISUP_EVENT_CVT:
ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
chanpos = ss7_find_cic_gripe(linkset, e->cvt.cic, e->cvt.opc, "CVT");
if (chanpos < 0) {
+ isup_free_call(ss7, e->cvt.call);
break;
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
+ p->ss7call = e->cvt.call;
sig_ss7_loopback(p, 1);
- sig_ss7_unlock_private(p);
-
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, e->cvt.call);
+ }
isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
+ sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_REL:
chanpos = ss7_find_cic_gripe(linkset, e->rel.cic, e->rel.opc, "REL");
if (chanpos < 0) {
- /* Continue hanging up the call anyway. */
- isup_rlc(ss7, e->rel.call);
+ isup_free_call(ss7, e->rel.call);
break;
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
+ p->ss7call = e->rel.call;
callid = func_ss7_linkset_callid(linkset, chanpos);
sig_ss7_lock_owner(linkset, chanpos);
if (p->owner) {
@@ -1170,128 +1965,193 @@ void *ss7_linkset(void *data)
ast_channel_hangupcause_set(p->owner, e->rel.cause);
ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+ p->do_hangup = SS7_HANGUP_SEND_RLC;
ast_channel_unlock(p->owner);
+ } else {
+ ast_verb(1, "REL on CIC %d DPC %d without owner!\n", p->cic, p->dpc);
+ isup_rlc(ss7, p->ss7call);
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
}
/* End the loopback if we have one */
sig_ss7_loopback(p, 0);
- isup_rlc(ss7, e->rel.call);
- p->ss7call = NULL;
-
+ /* the rel is not complete here!!! */
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_ACM:
chanpos = ss7_find_cic_gripe(linkset, e->acm.cic, e->acm.opc, "ACM");
if (chanpos < 0) {
- isup_rel(ss7, e->acm.call, -1);
+ isup_free_call(ss7, e->acm.call);
break;
}
- {
- p = linkset->pvts[chanpos];
- ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
+ p = linkset->pvts[chanpos];
- if (e->acm.call_ref_ident > 0) {
- p->rlt = 1; /* Setting it but not using it here*/
- }
+ ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
- sig_ss7_lock_private(p);
- callid = func_ss7_linkset_callid(linkset, chanpos);
- sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROCEEDING);
- if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
- p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
+ if (e->acm.call_ref_ident > 0) {
+ p->rlt = 1; /* Setting it but not using it here*/
+ }
+
+ sig_ss7_lock_private(p);
+ p->ss7call = e->acm.call;
+ callid = func_ss7_linkset_callid(linkset, chanpos);
+ sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROCEEDING);
+ if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
+ p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
+ }
+ sig_ss7_set_dialing(p, 0);
+ /* Send alerting if subscriber is free */
+ if (e->acm.called_party_status_ind == 1) {
+ if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
+ p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
}
- sig_ss7_set_dialing(p, 0);
- /* Send alerting if subscriber is free */
- if (e->acm.called_party_status_ind == 1) {
- if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
- p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
- }
- sig_ss7_lock_owner(linkset, chanpos);
- if (p->owner) {
- ast_setstate(p->owner, AST_STATE_RINGING);
- ast_channel_unlock(p->owner);
- }
- sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
+ sig_ss7_lock_owner(linkset, chanpos);
+ if (p->owner) {
+ ast_setstate(p->owner, AST_STATE_RINGING);
+ ast_channel_unlock(p->owner);
}
- sig_ss7_unlock_private(p);
+ sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
}
+ p->echocontrol_ind = e->acm.echocontrol_ind;
+ sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_CGB:
chanpos = ss7_find_cic_gripe(linkset, e->cgb.startcic, e->cgb.opc, "CGB");
if (chanpos < 0) {
+ isup_free_call(ss7, e->cgb.call);
break;
}
p = linkset->pvts[chanpos];
- ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, 1);
- isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
+ ss7_check_range(linkset, e->cgb.startcic, e->cgb.endcic,
+ e->cgb.opc, e->cgb.status);
+ ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic,
+ e->cgb.opc, e->cgb.status, 1, 1,
+ (e->cgb.type) ? SS7_BLOCKED_HARDWARE : SS7_BLOCKED_MAINTENANCE);
+
+ sig_ss7_lock_private(p);
+ p->ss7call = e->cgb.call;
+
+ isup_cgba(linkset->ss7, p->ss7call, e->cgb.endcic, e->cgb.status);
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, e->cgb.call);
+ }
+ sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_CGU:
chanpos = ss7_find_cic_gripe(linkset, e->cgu.startcic, e->cgu.opc, "CGU");
if (chanpos < 0) {
+ isup_free_call(ss7, e->cgu.call);
break;
}
p = linkset->pvts[chanpos];
- ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, 0);
- isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
+ ss7_check_range(linkset, e->cgu.startcic, e->cgu.endcic,
+ e->cgu.opc, e->cgu.status);
+ ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic,
+ e->cgu.opc, e->cgu.status, 0, 1,
+ e->cgu.type ? SS7_BLOCKED_HARDWARE : SS7_BLOCKED_MAINTENANCE);
+
+ sig_ss7_lock_private(p);
+ p->ss7call = e->cgu.call;
+
+ isup_cgua(linkset->ss7, p->ss7call, e->cgu.endcic, e->cgu.status);
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, e->cgu.call);
+ }
+ sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_UCIC:
chanpos = ss7_find_cic_gripe(linkset, e->ucic.cic, e->ucic.opc, "UCIC");
if (chanpos < 0) {
+ isup_free_call(ss7, e->ucic.call);
break;
}
p = linkset->pvts[chanpos];
ast_debug(1, "Unequiped Circuit Id Code on CIC %d\n", e->ucic.cic);
sig_ss7_lock_private(p);
- sig_ss7_set_remotelyblocked(p, 1);
+ sig_ss7_lock_owner(linkset, chanpos);
+ if (p->owner) {
+ ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+ ast_channel_unlock(p->owner);
+ }
+ sig_ss7_set_remotelyblocked(p, 1, SS7_BLOCKED_MAINTENANCE);
sig_ss7_set_inservice(p, 0);
+ p->ss7call = NULL;
+ isup_free_call(ss7, e->ucic.call);
sig_ss7_unlock_private(p);/* doesn't require a SS7 acknowledgement */
break;
case ISUP_EVENT_BLO:
chanpos = ss7_find_cic_gripe(linkset, e->blo.cic, e->blo.opc, "BLO");
if (chanpos < 0) {
+ isup_free_call(ss7, e->blo.call);
break;
}
p = linkset->pvts[chanpos];
ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
sig_ss7_lock_private(p);
- sig_ss7_set_remotelyblocked(p, 1);
+ p->ss7call = e->blo.call;
+ sig_ss7_set_remotelyblocked(p, 1, SS7_BLOCKED_MAINTENANCE);
+ isup_bla(linkset->ss7, e->blo.call);
+ sig_ss7_lock_owner(linkset, chanpos);
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, e->blo.call);
+ } else {
+ if (e->blo.got_sent_msg & ISUP_SENT_IAM) {
+ /* Q.784 6.2.2 */
+ ast_channel_hangupcause_set(p->owner, SS7_CAUSE_TRY_AGAIN);
+ }
+ ast_channel_unlock(p->owner);
+ }
sig_ss7_unlock_private(p);
- isup_bla(linkset->ss7, e->blo.cic, p->dpc);
break;
case ISUP_EVENT_BLA:
chanpos = ss7_find_cic_gripe(linkset, e->bla.cic, e->bla.opc, "BLA");
if (chanpos < 0) {
+ isup_free_call(ss7, e->bla.call);
break;
}
- ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
+ ast_debug(1, "Locally blocking CIC %d\n", e->bla.cic);
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
- sig_ss7_set_locallyblocked(p, 1);
+ p->ss7call = e->bla.call;
+ sig_ss7_set_locallyblocked(p, 1, SS7_BLOCKED_MAINTENANCE);
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
+ }
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_UBL:
chanpos = ss7_find_cic_gripe(linkset, e->ubl.cic, e->ubl.opc, "UBL");
if (chanpos < 0) {
+ isup_free_call(ss7, e->ubl.call);
break;
}
p = linkset->pvts[chanpos];
- ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
+ ast_debug(1, "Remotely unblocking CIC %d PC %d\n", e->ubl.cic, e->ubl.opc);
sig_ss7_lock_private(p);
- sig_ss7_set_remotelyblocked(p, 0);
+ p->ss7call = e->ubl.call;
+ sig_ss7_set_remotelyblocked(p, 0, SS7_BLOCKED_MAINTENANCE);
+ isup_uba(linkset->ss7, e->ubl.call);
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
+ }
sig_ss7_unlock_private(p);
- isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
break;
case ISUP_EVENT_UBA:
chanpos = ss7_find_cic_gripe(linkset, e->uba.cic, e->uba.opc, "UBA");
if (chanpos < 0) {
+ isup_free_call(ss7, e->uba.call);
break;
}
p = linkset->pvts[chanpos];
- ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
+ ast_debug(1, "Locally unblocking CIC %d PC %d\n", e->uba.cic, e->uba.opc);
sig_ss7_lock_private(p);
- sig_ss7_set_locallyblocked(p, 0);
+ p->ss7call = e->uba.call;
+ sig_ss7_set_locallyblocked(p, 0, SS7_BLOCKED_MAINTENANCE);
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
+ }
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_CON:
@@ -1299,49 +2159,92 @@ void *ss7_linkset(void *data)
if (e->e == ISUP_EVENT_CON) {
chanpos = ss7_find_cic_gripe(linkset, e->con.cic, e->con.opc, "CON");
if (chanpos < 0) {
- isup_rel(ss7, e->con.call, -1);
+ isup_free_call(ss7, e->con.call);
break;
}
} else {
chanpos = ss7_find_cic_gripe(linkset, e->anm.cic, e->anm.opc, "ANM");
if (chanpos < 0) {
- isup_rel(ss7, e->anm.call, -1);
+ isup_free_call(ss7, e->anm.call);
break;
}
}
- {
- p = linkset->pvts[chanpos];
- sig_ss7_lock_private(p);
- callid = func_ss7_linkset_callid(linkset, chanpos);
- if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
- p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ p->ss7call = (e->e == ISUP_EVENT_ANM) ? e->anm.call : e->con.call;
+ callid = func_ss7_linkset_callid(linkset, chanpos);
+ if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
+ p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
+ }
+
+ if (!ast_strlen_zero((e->e == ISUP_EVENT_ANM)
+ ? e->anm.connected_num : e->con.connected_num)) {
+ sig_ss7_lock_owner(linkset, chanpos);
+ if (p->owner) {
+ struct ast_party_connected_line ast_connected;
+ char connected_num[AST_MAX_EXTENSION];
+
+ ast_party_connected_line_init(&ast_connected);
+ if (e->e == ISUP_EVENT_ANM) {
+ ast_connected.id.number.presentation = ss7_pres_scr2cid_pres(
+ e->anm.connected_presentation_ind,
+ e->anm.connected_screening_ind);
+ ss7_apply_plan_to_number(connected_num, sizeof(connected_num),
+ linkset, e->anm.connected_num, e->anm.connected_nai);
+ ast_connected.id.number.str = ast_strdup(connected_num);
+ } else {
+ ast_connected.id.number.presentation = ss7_pres_scr2cid_pres(
+ e->con.connected_presentation_ind,
+ e->con.connected_screening_ind);
+ ss7_apply_plan_to_number(connected_num, sizeof(connected_num),
+ linkset, e->con.connected_num, e->con.connected_nai);
+ ast_connected.id.number.str = ast_strdup(connected_num);
+ }
+ ast_connected.id.number.valid = 1;
+ ast_connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(p->owner, &ast_connected, NULL);
+ ast_party_connected_line_free(&ast_connected);
+ ast_channel_unlock(p->owner);
}
- sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_ANSWER);
- sig_ss7_set_dialing(p, 0);
- sig_ss7_open_media(p);
+ }
+
+ sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_ANSWER);
+ sig_ss7_set_dialing(p, 0);
+ sig_ss7_open_media(p);
+ if (((e->e == ISUP_EVENT_ANM) ? !e->anm.echocontrol_ind :
+ !e->con.echocontrol_ind) || !(linkset->flags & LINKSET_FLAG_USEECHOCONTROL)) {
sig_ss7_set_echocanceller(p, 1);
- sig_ss7_unlock_private(p);
}
+ sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_RLC:
- /* XXX Call ptr should be passed up from libss7! */
chanpos = ss7_find_cic_gripe(linkset, e->rlc.cic, e->rlc.opc, "RLC");
if (chanpos < 0) {
+ isup_free_call(ss7, e->rlc.call);
break;
}
- {
- p = linkset->pvts[chanpos];
- sig_ss7_lock_private(p);
- callid = func_ss7_linkset_callid(linkset, chanpos);
- if (p->alreadyhungup) {
- if (!p->owner) {
- p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
- }
- p->ss7call = NULL;
+
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ p->ss7call = e->rlc.call;
+ callid = func_ss7_linkset_callid(linkset, chanpos);
+ if (e->rlc.got_sent_msg & (ISUP_SENT_RSC | ISUP_SENT_REL)) {
+ sig_ss7_loopback(p, 0);
+ if (e->rlc.got_sent_msg & ISUP_SENT_RSC) {
+ sig_ss7_set_inservice(p, 1);
}
- sig_ss7_unlock_private(p);
}
+ sig_ss7_lock_owner(linkset, chanpos);
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, e->rlc.call);
+ p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
+ } else {
+ p->do_hangup = SS7_HANGUP_DO_NOTHING;
+ ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+ ast_channel_unlock(p->owner);
+ }
+ sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_FAA:
/*!
@@ -1350,25 +2253,87 @@ void *ss7_linkset(void *data)
*/
chanpos = ss7_find_cic_gripe(linkset, e->faa.cic, e->faa.opc, "FAA");
if (chanpos < 0) {
- isup_rel(linkset->ss7, e->faa.call, -1);
+ isup_free_call(ss7, e->faa.call);
break;
}
- {
- /* XXX FAR and FAA used for something dealing with transfers? */
- p = linkset->pvts[chanpos];
- ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
- sig_ss7_lock_private(p);
- callid = func_ss7_linkset_callid(linkset, chanpos);
- if (p->alreadyhungup){
- if (!p->owner) {
- p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
- }
- /* XXX We seem to be leaking the isup call structure here. */
- p->ss7call = NULL;
- ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR. Ignoring.\n");
- }
- sig_ss7_unlock_private(p);
+
+ /* XXX FAR and FAA used for something dealing with transfers? */
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ callid = func_ss7_linkset_callid(linkset, chanpos);
+ ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
+ p->ss7call = isup_free_call_if_clear(ss7, e->faa.call);
+ sig_ss7_unlock_private(p);
+ break;
+ case ISUP_EVENT_CGBA:
+ chanpos = ss7_find_cic_gripe(linkset, e->cgba.startcic, e->cgba.opc, "CGBA");
+ if (chanpos < 0) { /* Never will be true */
+ isup_free_call(ss7, e->cgba.call);
+ break;
+ }
+
+ ss7_block_cics(linkset, e->cgba.startcic, e->cgba.endcic,
+ e->cgba.opc, e->cgba.status, 1, 0,
+ e->cgba.type ? SS7_BLOCKED_HARDWARE : SS7_BLOCKED_MAINTENANCE);
+
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ p->ss7call = e->cgba.call;
+
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
}
+ sig_ss7_unlock_private(p);
+ break;
+ case ISUP_EVENT_CGUA:
+ chanpos = ss7_find_cic_gripe(linkset, e->cgua.startcic, e->cgua.opc, "CGUA");
+ if (chanpos < 0) { /* Never will be true */
+ isup_free_call(ss7, e->cgua.call);
+ break;
+ }
+
+ ss7_block_cics(linkset, e->cgua.startcic, e->cgua.endcic,
+ e->cgua.opc, e->cgua.status, 0, 0,
+ e->cgba.type ? SS7_BLOCKED_HARDWARE : SS7_BLOCKED_MAINTENANCE);
+
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ p->ss7call = e->cgua.call;
+
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
+ }
+ sig_ss7_unlock_private(p);
+ break;
+ case ISUP_EVENT_SUS:
+ chanpos = ss7_find_cic_gripe(linkset, e->sus.cic, e->sus.opc, "SUS");
+ if (chanpos < 0) {
+ isup_free_call(ss7, e->sus.call);
+ break;
+ }
+
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ p->ss7call = e->sus.call;
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
+ }
+ sig_ss7_unlock_private(p);
+ break;
+ case ISUP_EVENT_RES:
+ chanpos = ss7_find_cic_gripe(linkset, e->res.cic, e->res.opc, "RES");
+ if (chanpos < 0) {
+ isup_free_call(ss7, e->res.call);
+ break;
+ }
+
+ p = linkset->pvts[chanpos];
+ sig_ss7_lock_private(p);
+ p->ss7call = e->res.call;
+ if (!p->owner) {
+ p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
+ }
+ sig_ss7_unlock_private(p);
break;
default:
ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
@@ -1387,9 +2352,15 @@ void *ss7_linkset(void *data)
return 0;
}
-static inline void ss7_rel(struct sig_ss7_linkset *ss7)
+static void ss7_rel(struct sig_ss7_linkset *ss7)
{
+ /* Release the lock first */
ast_mutex_unlock(&ss7->lock);
+
+ /* Then break the poll to send our messages */
+ if (ss7->master != AST_PTHREADT_NULL) {
+ pthread_kill(ss7->master, SIGURG);
+ }
}
static void ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7)
@@ -1399,10 +2370,177 @@ static void ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7)
/* Avoid deadlock */
sig_ss7_deadlock_avoidance_private(pvt);
}
- /* Then break the poll */
- if (ss7->master != AST_PTHREADT_NULL) {
- pthread_kill(ss7->master, SIGURG);
+}
+
+/*!
+ * \brief Reset a specific CIC.
+ * \since 11.0
+ *
+ * \param linkset linkset control structure.
+ * \param cic Circuit Identification Code
+ * \param dpc Destination Point Code
+ *
+ * \return TRUE on success
+ */
+int sig_ss7_reset_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
+{
+ int i;
+
+ ast_mutex_lock(&linkset->lock);
+ for (i = 0; i < linkset->numchans; i++) {
+ if (linkset->pvts[i] && linkset->pvts[i]->cic == cic && linkset->pvts[i]->dpc == dpc) {
+ int res;
+
+ sig_ss7_lock_private(linkset->pvts[i]);
+ sig_ss7_set_locallyblocked(linkset->pvts[i], 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
+ res = ss7_start_rsc(linkset, i);
+ sig_ss7_unlock_private(linkset->pvts[i]);
+ ss7_rel(linkset); /* Also breaks the poll to send our messages */
+ return res;
+ }
}
+ ss7_rel(linkset);
+
+ return 0;
+}
+
+/*!
+ * \brief Block or Unblock a specific CIC.
+ * \since 11.0
+ *
+ * \param linkset linkset control structure.
+ * \param do_block Action to perform. Block if TRUE.
+ * \param which On which CIC to perform the operation.
+ *
+ * \return 0 on success
+ */
+int sig_ss7_cic_blocking(struct sig_ss7_linkset *linkset, int do_block, int which)
+{
+ ast_mutex_lock(&linkset->lock);
+ sig_ss7_lock_private(linkset->pvts[which]);
+ if (!ss7_find_alloc_call(linkset->pvts[which])) {
+ sig_ss7_unlock_private(linkset->pvts[which]);
+ ss7_rel(linkset);
+ return -1;
+ }
+
+ if (do_block) {
+ isup_blo(linkset->ss7, linkset->pvts[which]->ss7call);
+ } else {
+ isup_ubl(linkset->ss7, linkset->pvts[which]->ss7call);
+ }
+
+ sig_ss7_unlock_private(linkset->pvts[which]);
+ ss7_rel(linkset); /* Also breaks the poll to send our messages */
+
+ return 0;
+}
+
+/*!
+ * \brief Block or Unblock a range of CICs.
+ * \since 11.0
+ *
+ * \param linkset linkset control structure.
+ * \param do_block Action to perform. Block if TRUE.
+ * \param chanpos Channel position to start from.
+ * \param endcic Circuit Identification Code of the end of the range.
+ * \param state Array of CIC blocking status.
+ * \param type Type of the blocking - maintenance or hardware
+ *
+ * \note Assumes the linkset->lock is already obtained.
+ *
+ * \return 0 on success
+ */
+int sig_ss7_group_blocking(struct sig_ss7_linkset *linkset, int do_block, int chanpos, int endcic, unsigned char state[], int type)
+{
+ sig_ss7_lock_private(linkset->pvts[chanpos]);
+ if (!ss7_find_alloc_call(linkset->pvts[chanpos])) {
+ sig_ss7_unlock_private(linkset->pvts[chanpos]);
+ return -1;
+ }
+
+ if (do_block) {
+ isup_cgb(linkset->ss7, linkset->pvts[chanpos]->ss7call, endcic, state, type);
+ } else {
+ isup_cgu(linkset->ss7, linkset->pvts[chanpos]->ss7call, endcic, state, type);
+ }
+
+ sig_ss7_unlock_private(linkset->pvts[chanpos]);
+ return 0;
+}
+
+/*!
+ * \brief Reset a group of CICs.
+ * \since 11.0
+ *
+ * \param linkset linkset control structure.
+ * \param cic Circuit Identification Code
+ * \param dpc Destination Point Code
+ * \param range Range of the CICs to reset
+ *
+ * \note Assumes the linkset->lock is already obtained.
+ *
+ * \return 0 on success
+ */
+int sig_ss7_reset_group(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, int range)
+{
+ int i;
+
+ for (i = 0; i < linkset->numchans; i++) {
+ if (linkset->pvts[i] && linkset->pvts[i]->cic == cic && linkset->pvts[i]->dpc == dpc) {
+ ss7_clear_channels(linkset, cic, cic + range, dpc, SS7_HANGUP_FREE_CALL);
+ ss7_block_cics(linkset, cic, cic + range, dpc, NULL, 0, 1,
+ SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
+ ss7_block_cics(linkset, cic, cic + range, dpc, NULL, 0, 0,
+ SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
+
+ sig_ss7_lock_private(linkset->pvts[i]);
+ if (!ss7_find_alloc_call(linkset->pvts[i])) {
+ sig_ss7_unlock_private(linkset->pvts[i]);
+ return -1;
+ }
+ isup_grs(linkset->ss7, linkset->pvts[i]->ss7call, linkset->pvts[i]->cic + range);
+ sig_ss7_unlock_private(linkset->pvts[i]);
+ break;
+ }
+ }
+ return 0;
+}
+
+void sig_ss7_free_isup_call(struct sig_ss7_linkset *linkset, int channel)
+{
+ sig_ss7_lock_private(linkset->pvts[channel]);
+ if (linkset->pvts[channel]->ss7call) {
+ isup_free_call(linkset->ss7, linkset->pvts[channel]->ss7call);
+ linkset->pvts[channel]->ss7call = NULL;
+ }
+ sig_ss7_unlock_private(linkset->pvts[channel]);
+}
+
+static int ss7_parse_prefix(struct sig_ss7_chan *p, const char *number, char *nai)
+{
+ int strip = 0;
+
+ if (strncmp(number, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
+ strip = strlen(p->ss7->internationalprefix);
+ *nai = SS7_NAI_INTERNATIONAL;
+ } else if (strncmp(number, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
+ strip = strlen(p->ss7->nationalprefix);
+ *nai = SS7_NAI_NATIONAL;
+ } else if (strncmp(number, p->ss7->networkroutedprefix, strlen(p->ss7->networkroutedprefix)) == 0) {
+ strip = strlen(p->ss7->networkroutedprefix);
+ *nai = SS7_NAI_NETWORKROUTED;
+ } else if (strncmp(number, p->ss7->unknownprefix, strlen(p->ss7->unknownprefix)) == 0) {
+ strip = strlen(p->ss7->unknownprefix);
+ *nai = SS7_NAI_UNKNOWN;
+ } else if (strncmp(number, p->ss7->subscriberprefix, strlen(p->ss7->subscriberprefix)) == 0) {
+ strip = strlen(p->ss7->subscriberprefix);
+ *nai = SS7_NAI_SUBSCRIBER;
+ } else {
+ *nai = SS7_NAI_SUBSCRIBER;
+ }
+
+ return strip;
}
/*!
@@ -1453,7 +2591,7 @@ void sig_ss7_link_noalarm(struct sig_ss7_linkset *linkset, int which)
* \retval 0 on success.
* \retval -1 on error.
*/
-int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode)
+int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode, int cur_slc)
{
if (!linkset->ss7) {
linkset->type = ss7type;
@@ -1467,7 +2605,7 @@ int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type,
ss7_set_network_ind(linkset->ss7, networkindicator);
ss7_set_pc(linkset->ss7, pointcode);
- if (ss7_add_link(linkset->ss7, transport, linkset->fds[which])) {
+ if (ss7_add_link(linkset->ss7, transport, linkset->fds[which], cur_slc, adjpointcode)) {
ast_log(LOG_WARNING, "Could not add SS7 link!\n");
}
@@ -1479,8 +2617,6 @@ int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type,
ss7_link_noalarm(linkset->ss7, linkset->fds[which]);
}
- ss7_set_adjpc(linkset->ss7, linkset->fds[which], adjpointcode);
-
return 0;
}
@@ -1505,7 +2641,13 @@ int sig_ss7_available(struct sig_ss7_chan *p)
ast_mutex_lock(&p->ss7->lock);
available = sig_ss7_is_chan_available(p);
if (available) {
- p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
+ p->ss7call = isup_new_call(p->ss7->ss7, p->cic, p->dpc, 1);
+ if (!p->ss7call) {
+ ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
+ available = 0;
+ } else {
+ p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
+ }
}
ast_mutex_unlock(&p->ss7->lock);
@@ -1522,6 +2664,159 @@ static unsigned char cid_pres2ss7screen(int cid_pres)
return cid_pres & 0x03;
}
+static void ss7_connected_line_update(struct sig_ss7_chan *p, struct ast_party_connected_line *connected)
+{
+ int connected_strip = 0;
+ char connected_nai;
+ unsigned char connected_pres;
+ unsigned char connected_screen;
+ const char *connected_num;
+
+ if (!connected->id.number.valid) {
+ return;
+ }
+
+ connected_num = S_OR(connected->id.number.str, "");
+ if (p->ss7->called_nai == SS7_NAI_DYNAMIC) {
+ connected_strip = ss7_parse_prefix(p, connected_num, &connected_nai);
+ } else {
+ connected_nai = p->ss7->called_nai;
+ }
+
+ connected_pres = cid_pres2ss7pres(connected->id.number.presentation);
+ connected_screen = cid_pres2ss7screen(connected->id.number.presentation);
+
+ isup_set_connected(p->ss7call, connected_num + connected_strip, connected_nai, connected_pres, connected_screen);
+}
+
+static unsigned char ss7_redirect_reason(struct sig_ss7_chan *p, struct ast_party_redirecting *redirecting, int orig)
+{
+ int reason = (orig) ? redirecting->orig_reason.code : redirecting->reason.code;
+
+ switch (reason) {
+ case AST_REDIRECTING_REASON_USER_BUSY:
+ return SS7_REDIRECTING_REASON_USER_BUSY;
+ case AST_REDIRECTING_REASON_NO_ANSWER:
+ return SS7_REDIRECTING_REASON_NO_ANSWER;
+ case AST_REDIRECTING_REASON_UNCONDITIONAL:
+ return SS7_REDIRECTING_REASON_UNCONDITIONAL;
+ }
+
+ if (orig || reason == AST_REDIRECTING_REASON_UNKNOWN) {
+ return SS7_REDIRECTING_REASON_UNKNOWN;
+ }
+
+ if (reason == AST_REDIRECTING_REASON_UNAVAILABLE) {
+ return SS7_REDIRECTING_REASON_UNAVAILABLE;
+ }
+
+ if (reason == AST_REDIRECTING_REASON_DEFLECTION) {
+ if (p->call_level > SIG_SS7_CALL_LEVEL_PROCEEDING) {
+ return SS7_REDIRECTING_REASON_DEFLECTION_DURING_ALERTING;
+ }
+ return SS7_REDIRECTING_REASON_DEFLECTION_IMMEDIATE_RESPONSE;
+ }
+
+ return SS7_REDIRECTING_REASON_UNKNOWN;
+}
+
+static unsigned char ss7_redirect_info_ind(struct ast_channel *ast)
+{
+ const char *redirect_info_ind;
+ struct ast_party_redirecting *redirecting = ast_channel_redirecting(ast);
+
+ redirect_info_ind = pbx_builtin_getvar_helper(ast, "SS7_REDIRECT_INFO_IND");
+ if (!ast_strlen_zero(redirect_info_ind)) {
+ if (!strcasecmp(redirect_info_ind, "CALL_REROUTED_PRES_ALLOWED")) {
+ return SS7_INDICATION_REROUTED_PRES_ALLOWED;
+ }
+ if (!strcasecmp(redirect_info_ind, "CALL_REROUTED_INFO_RESTRICTED")) {
+ return SS7_INDICATION_REROUTED_INFO_RESTRICTED;
+ }
+ if (!strcasecmp(redirect_info_ind, "CALL_DIVERTED_PRES_ALLOWED")) {
+ return SS7_INDICATION_DIVERTED_PRES_ALLOWED;
+ }
+ if (!strcasecmp(redirect_info_ind, "CALL_DIVERTED_INFO_RESTRICTED")) {
+ return SS7_INDICATION_DIVERTED_INFO_RESTRICTED;
+ }
+ if (!strcasecmp(redirect_info_ind, "CALL_REROUTED_PRES_RESTRICTED")) {
+ return SS7_INDICATION_REROUTED_PRES_RESTRICTED;
+ }
+ if (!strcasecmp(redirect_info_ind, "CALL_DIVERTED_PRES_RESTRICTED")) {
+ return SS7_INDICATION_DIVERTED_PRES_RESTRICTED;
+ }
+ if (!strcasecmp(redirect_info_ind, "SPARE")) {
+ return SS7_INDICATION_SPARE;
+ }
+ return SS7_INDICATION_NO_REDIRECTION;
+ }
+
+ if (redirecting->reason.code == AST_REDIRECTING_REASON_DEFLECTION) {
+ if ((redirecting->to.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
+ if ((redirecting->orig.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
+ return SS7_INDICATION_DIVERTED_PRES_ALLOWED;
+ }
+ return SS7_INDICATION_DIVERTED_PRES_RESTRICTED;
+ }
+ return SS7_INDICATION_DIVERTED_INFO_RESTRICTED;
+ }
+
+ if ((redirecting->to.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
+ if ((redirecting->orig.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
+ return SS7_INDICATION_REROUTED_PRES_ALLOWED;
+ }
+ return SS7_INDICATION_REROUTED_PRES_RESTRICTED;
+ }
+ return SS7_INDICATION_REROUTED_INFO_RESTRICTED;
+}
+
+static void ss7_redirecting_update(struct sig_ss7_chan *p, struct ast_channel *ast)
+{
+ int num_nai_strip = 0;
+ struct ast_party_redirecting *redirecting = ast_channel_redirecting(ast);
+
+ if (!redirecting->count) {
+ return;
+ }
+
+ isup_set_redirect_counter(p->ss7call, redirecting->count);
+
+ if (redirecting->orig.number.valid) {
+ char ss7_orig_called_nai = p->ss7->called_nai;
+ const char *ss7_orig_called_num = S_OR(redirecting->orig.number.str, "");
+
+ if (ss7_orig_called_nai == SS7_NAI_DYNAMIC) {
+ num_nai_strip = ss7_parse_prefix(p, ss7_orig_called_num, &ss7_orig_called_nai);
+ } else {
+ num_nai_strip = 0;
+ }
+ isup_set_orig_called_num(p->ss7call, ss7_orig_called_num + num_nai_strip,
+ ss7_orig_called_nai,
+ cid_pres2ss7pres(redirecting->orig.number.presentation),
+ cid_pres2ss7screen(redirecting->orig.number.presentation));
+ }
+
+ if (redirecting->from.number.valid) {
+ char ss7_redirecting_num_nai = p->ss7->calling_nai;
+ const char *redirecting_number = S_OR(redirecting->from.number.str, "");
+
+ if (ss7_redirecting_num_nai == SS7_NAI_DYNAMIC) {
+ num_nai_strip = ss7_parse_prefix(p, redirecting_number, &ss7_redirecting_num_nai);
+ } else {
+ num_nai_strip = 0;
+ }
+
+ isup_set_redirecting_number(p->ss7call, redirecting_number + num_nai_strip,
+ ss7_redirecting_num_nai,
+ cid_pres2ss7pres(redirecting->from.number.presentation),
+ cid_pres2ss7screen(redirecting->from.number.presentation));
+ }
+
+ isup_set_redirection_info(p->ss7call, ss7_redirect_info_ind(ast),
+ ss7_redirect_reason(p, ast_channel_redirecting(ast), 1),
+ redirecting->count, ss7_redirect_reason(p, ast_channel_redirecting(ast), 0));
+}
+
/*!
* \brief Dial out using the specified SS7 channel.
* \since 1.8
@@ -1539,6 +2834,13 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
int called_nai_strip;
char ss7_calling_nai;
int calling_nai_strip;
+ const char *col_req = NULL;
+ const char *ss7_cug_indicator_str;
+ const char *ss7_cug_interlock_ni;
+ const char *ss7_cug_interlock_code;
+ const char *ss7_interworking_indicator;
+ const char *ss7_forward_indicator_pmbits;
+ unsigned char ss7_cug_indicator;
const char *charge_str = NULL;
const char *gen_address = NULL;
const char *gen_digits = NULL;
@@ -1551,6 +2853,7 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
const char *call_ref_id = NULL;
const char *call_ref_pc = NULL;
const char *send_far = NULL;
+ const char *tmr = NULL;
char *c;
char *l;
char dest[256];
@@ -1582,47 +2885,27 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
return -1;
}
- p->ss7call = isup_new_call(p->ss7->ss7);
- if (!p->ss7call) {
- ss7_rel(p->ss7);
- ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
- return -1;
- }
-
called_nai_strip = 0;
ss7_called_nai = p->ss7->called_nai;
if (ss7_called_nai == SS7_NAI_DYNAMIC) { /* compute dynamically */
- if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
- called_nai_strip = strlen(p->ss7->internationalprefix);
- ss7_called_nai = SS7_NAI_INTERNATIONAL;
- } else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
- called_nai_strip = strlen(p->ss7->nationalprefix);
- ss7_called_nai = SS7_NAI_NATIONAL;
- } else {
- ss7_called_nai = SS7_NAI_SUBSCRIBER;
- }
+ called_nai_strip = ss7_parse_prefix(p, c + p->stripmsd, &ss7_called_nai);
}
isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
calling_nai_strip = 0;
ss7_calling_nai = p->ss7->calling_nai;
if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) { /* compute dynamically */
- if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
- calling_nai_strip = strlen(p->ss7->internationalprefix);
- ss7_calling_nai = SS7_NAI_INTERNATIONAL;
- } else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
- calling_nai_strip = strlen(p->ss7->nationalprefix);
- ss7_calling_nai = SS7_NAI_NATIONAL;
- } else {
- ss7_calling_nai = SS7_NAI_SUBSCRIBER;
- }
+ calling_nai_strip = ss7_parse_prefix(p, l, &ss7_calling_nai);
}
+
isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
- p->use_callingpres ? cid_pres2ss7pres(ast_channel_connected(ast)->id.number.presentation) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
+ p->use_callingpres ? cid_pres2ss7pres(ast_channel_connected(ast)->id.number.presentation)
+ : (l ? SS7_PRESENTATION_ALLOWED
+ : (ast_channel_connected(ast)->id.number.presentation == AST_PRES_UNAVAILABLE
+ ? SS7_PRESENTATION_ADDR_NOT_AVAILABLE : SS7_PRESENTATION_RESTRICTED)),
p->use_callingpres ? cid_pres2ss7screen(ast_channel_connected(ast)->id.number.presentation) : SS7_SCREENING_USER_PROVIDED);
isup_set_oli(p->ss7call, ast_channel_connected(ast)->ani2);
- isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
/* Set the charge number if it is set */
charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
@@ -1664,10 +2947,66 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
}
send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR");
- if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
- (isup_far(p->ss7->ss7, p->ss7call));
+ if (send_far && strncmp("NO", send_far, strlen(send_far)) != 0) {
+ isup_far(p->ss7->ss7, p->ss7call);
+ }
+
+ tmr = pbx_builtin_getvar_helper(ast, "SS7_TMR_NUM");
+ if (tmr) {
+ isup_set_tmr(p->ss7call, atoi(tmr));
+ } else if ((tmr = pbx_builtin_getvar_helper(ast, "SS7_TMR")) && tmr[0] != '\0') {
+ if (!strcasecmp(tmr, "SPEECH")) {
+ isup_set_tmr(p->ss7call, SS7_TMR_SPEECH);
+ } else if (!strcasecmp(tmr, "SPARE")) {
+ isup_set_tmr(p->ss7call, SS7_TMR_SPARE);
+ } else if (!strcasecmp(tmr, "3K1_AUDIO")) {
+ isup_set_tmr(p->ss7call, SS7_TMR_3K1_AUDIO);
+ } else if (!strcasecmp(tmr, "64K_UNRESTRICTED")) {
+ isup_set_tmr(p->ss7call, SS7_TMR_64K_UNRESTRICTED);
+ } else {
+ isup_set_tmr(p->ss7call, SS7_TMR_N64K_OR_SPARE);
+ }
+ }
+
+ col_req = pbx_builtin_getvar_helper(ast, "SS7_COL_REQUEST");
+ if (ast_true(col_req)) {
+ isup_set_col_req(p->ss7call);
+ }
+
+ ss7_cug_indicator_str = pbx_builtin_getvar_helper(ast, "SS7_CUG_INDICATOR");
+ if (!ast_strlen_zero(ss7_cug_indicator_str)) {
+ if (!strcasecmp(ss7_cug_indicator_str, "OUTGOING_ALLOWED")) {
+ ss7_cug_indicator = ISUP_CUG_OUTGOING_ALLOWED;
+ } else if (!strcasecmp(ss7_cug_indicator_str, "OUTGOING_NOT_ALLOWED")) {
+ ss7_cug_indicator = ISUP_CUG_OUTGOING_NOT_ALLOWED;
+ } else {
+ ss7_cug_indicator = ISUP_CUG_NON;
+ }
+
+ if (ss7_cug_indicator != ISUP_CUG_NON) {
+ ss7_cug_interlock_code = pbx_builtin_getvar_helper(ast, "SS7_CUG_INTERLOCK_CODE");
+ ss7_cug_interlock_ni = pbx_builtin_getvar_helper(ast, "SS7_CUG_INTERLOCK_NI");
+ if (ss7_cug_interlock_code && ss7_cug_interlock_ni && strlen(ss7_cug_interlock_ni) == 4) {
+ isup_set_cug(p->ss7call, ss7_cug_indicator, ss7_cug_interlock_ni, atoi(ss7_cug_interlock_code));
+ }
+ }
+ }
+
+ ss7_redirecting_update(p, ast);
+
+ isup_set_echocontrol(p->ss7call, (p->ss7->flags & LINKSET_FLAG_DEFAULTECHOCONTROL) ? 1 : 0);
+ ss7_interworking_indicator = pbx_builtin_getvar_helper(ast, "SS7_INTERWORKING_INDICATOR");
+ if (ss7_interworking_indicator) {
+ isup_set_interworking_indicator(p->ss7call, ast_true(ss7_interworking_indicator));
+ }
+
+ ss7_forward_indicator_pmbits = pbx_builtin_getvar_helper(ast, "SS7_FORWARD_INDICATOR_PMBITS");
+ if (ss7_forward_indicator_pmbits) {
+ isup_set_forward_indicator_pmbits(p->ss7call, atoi(ss7_forward_indicator_pmbits));
+ }
p->call_level = SIG_SS7_CALL_LEVEL_SETUP;
+ p->do_hangup = SS7_HANGUP_SEND_REL;
isup_iam(p->ss7->ss7, p->ss7call);
sig_ss7_set_dialing(p, 1);
ast_setstate(ast, AST_STATE_DIALING);
@@ -1687,8 +3026,6 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
*/
int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
{
- int res = 0;
-
if (!ast_channel_tech_pvt(ast)) {
ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
return 0;
@@ -1704,22 +3041,51 @@ int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
ss7_grab(p, p->ss7);
p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
if (p->ss7call) {
- if (!p->alreadyhungup) {
- const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
- int icause = ast_channel_hangupcause(ast) ? ast_channel_hangupcause(ast) : -1;
-
- if (cause) {
- if (atoi(cause)) {
- icause = atoi(cause);
+ switch (p->do_hangup) {
+ case SS7_HANGUP_SEND_REL:
+ {
+ const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
+ int icause = ast_channel_hangupcause(ast) ? ast_channel_hangupcause(ast) : -1;
+
+ if (cause) {
+ if (atoi(cause)) {
+ icause = atoi(cause);
+ }
+ }
+ if (icause > 255) {
+ icause = 16;
}
+
+ isup_rel(p->ss7->ss7, p->ss7call, icause);
+ p->do_hangup = SS7_HANGUP_DO_NOTHING;
}
- isup_rel(p->ss7->ss7, p->ss7call, icause);
- p->alreadyhungup = 1;
+ break;
+ case SS7_HANGUP_SEND_RSC:
+ ss7_do_rsc(p);
+ p->do_hangup = SS7_HANGUP_DO_NOTHING;
+ break;
+ case SS7_HANGUP_SEND_RLC:
+ isup_rlc(p->ss7->ss7, p->ss7call);
+ p->do_hangup = SS7_HANGUP_DO_NOTHING;
+ p->ss7call = isup_free_call_if_clear(p->ss7->ss7, p->ss7call);
+ break;
+ case SS7_HANGUP_FREE_CALL:
+ p->do_hangup = SS7_HANGUP_DO_NOTHING;
+ isup_free_call(p->ss7->ss7, p->ss7call);
+ p->ss7call = NULL;
+ break;
+ case SS7_HANGUP_REEVENT_IAM:
+ isup_event_iam(p->ss7->ss7, p->ss7call, p->dpc);
+ p->do_hangup = SS7_HANGUP_SEND_REL;
+ break;
+ case SS7_HANGUP_DO_NOTHING:
+ p->ss7call = isup_free_call_if_clear(p->ss7->ss7, p->ss7call);
+ break;
}
}
ss7_rel(p->ss7);
- return res;
+ return 0;
}
/*!
@@ -1738,10 +3104,14 @@ int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast)
ss7_grab(p, p->ss7);
if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
+ if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING && (p->ss7->flags & LINKSET_FLAG_AUTOACM)) {
+ isup_acm(p->ss7->ss7, p->ss7call);
+ }
p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
}
- sig_ss7_open_media(p);
+
res = isup_anm(p->ss7->ss7, p->ss7call);
+ sig_ss7_open_media(p);
ss7_rel(p->ss7);
return res;
}
@@ -1764,7 +3134,7 @@ void sig_ss7_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, str
}
/*!
- * \brief SS7 answer channel.
+ * \brief SS7 indication.
* \since 1.8
*
* \param p Signaling private structure pointer.
@@ -1793,15 +3163,20 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
case AST_CONTROL_RINGING:
ss7_grab(p, p->ss7);
if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
- p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) {
p->rlt = 1;
}
+ if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING && (p->ss7->flags & LINKSET_FLAG_AUTOACM)) {
+ isup_acm(p->ss7->ss7, p->ss7call);
+ }
+
/* No need to send CPG if call will be RELEASE */
if (p->rlt != 1) {
isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
}
+
+ p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
}
ss7_rel(p->ss7);
@@ -1833,15 +3208,15 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",ast_channel_name(chan));
ss7_grab(p, p->ss7);
if (!p->progress && p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
- p->progress = 1;/* No need to send inband-information progress again. */
+ p->progress = 1; /* No need to send inband-information progress again. */
isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
- ss7_rel(p->ss7);
/* enable echo canceler here on SS7 calls */
- sig_ss7_set_echocanceller(p, 1);
- } else {
- ss7_rel(p->ss7);
+ if (!p->echocontrol_ind || !(p->ss7->flags & LINKSET_FLAG_USEECHOCONTROL)) {
+ sig_ss7_set_echocanceller(p, 1);
+ }
}
+ ss7_rel(p->ss7);
/* don't continue in ast_indicate */
res = 0;
break;
@@ -1873,6 +3248,14 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
case AST_CONTROL_SRCUPDATE:
res = 0;
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ ss7_connected_line_update(p, ast_channel_connected(chan));
+ res = 0;
+ break;
+ case AST_CONTROL_REDIRECTING:
+ ss7_redirecting_update(p, chan);
+ res = 0;
+ break;
case -1:
res = sig_ss7_play_tone(p, -1);
break;
@@ -1914,6 +3297,7 @@ struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law
/* Release the allocated channel. Only have to deal with the linkset lock. */
ast_mutex_lock(&p->ss7->lock);
p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
+ isup_free_call(p->ss7->ss7, p->ss7call);
ast_mutex_unlock(&p->ss7->lock);
}
return ast;
diff --git a/channels/sig_ss7.h b/channels/sig_ss7.h
index 56d393c81..e2bc8e436 100644
--- a/channels/sig_ss7.h
+++ b/channels/sig_ss7.h
@@ -66,6 +66,13 @@ extern "C" {
#define SS7_NAI_DYNAMIC -1
#define LINKSET_FLAG_EXPLICITACM (1 << 0)
+#define LINKSET_FLAG_INITIALHWBLO (1 << 1)
+#define LINKSET_FLAG_USEECHOCONTROL (1 << 2)
+#define LINKSET_FLAG_DEFAULTECHOCONTROL (1 << 3)
+#define LINKSET_FLAG_AUTOACM (1 << 4)
+
+#define SS7_BLOCKED_MAINTENANCE (1 << 0)
+#define SS7_BLOCKED_HARDWARE (1 << 1)
enum sig_ss7_tone {
@@ -84,6 +91,27 @@ enum sig_ss7_law {
SIG_SS7_ALAW
};
+enum sig_ss7_redirect_idication {
+ SS7_INDICATION_NO_REDIRECTION = 0,
+ SS7_INDICATION_REROUTED_PRES_ALLOWED,
+ SS7_INDICATION_REROUTED_INFO_RESTRICTED,
+ SS7_INDICATION_DIVERTED_PRES_ALLOWED,
+ SS7_INDICATION_DIVERTED_INFO_RESTRICTED,
+ SS7_INDICATION_REROUTED_PRES_RESTRICTED,
+ SS7_INDICATION_DIVERTED_PRES_RESTRICTED,
+ SS7_INDICATION_SPARE
+};
+
+enum sig_ss7_redirect_reason {
+ SS7_REDIRECTING_REASON_UNKNOWN = 0,
+ SS7_REDIRECTING_REASON_USER_BUSY,
+ SS7_REDIRECTING_REASON_NO_ANSWER,
+ SS7_REDIRECTING_REASON_UNCONDITIONAL,
+ SS7_REDIRECTING_REASON_DEFLECTION_DURING_ALERTING,
+ SS7_REDIRECTING_REASON_DEFLECTION_IMMEDIATE_RESPONSE,
+ SS7_REDIRECTING_REASON_UNAVAILABLE
+};
+
/*! Call establishment life cycle level for simple comparisons. */
enum sig_ss7_call_level {
/*! Call does not exist. */
@@ -118,8 +146,6 @@ enum sig_ss7_call_level {
* We have sent or received CON/ANM.
*/
SIG_SS7_CALL_LEVEL_CONNECT,
- /*! Call has collided with incoming call. */
- SIG_SS7_CALL_LEVEL_GLARE,
};
struct sig_ss7_linkset;
@@ -153,6 +179,8 @@ struct sig_ss7_callback {
void (* const queue_control)(void *pvt, int subclass);
void (* const open_media)(void *pvt);
+
+ struct sig_ss7_linkset *(* const find_linkset)(struct ss7 *ss7);
};
/*! Global sig_ss7 callbacks to the upper layer. */
@@ -192,10 +220,19 @@ struct sig_ss7_chan {
unsigned int use_callingpres:1;
unsigned int immediate:1; /*!< Answer before getting digits? */
- /*! \brief TRUE if the channel is locally blocked. Set by user and link. */
- unsigned int locallyblocked:1;
- /*! \brief TRUE if the channel is remotely blocked. Set by user and link. */
- unsigned int remotelyblocked:1;
+ /*!
+ * \brief Bitmask for the channel being locally blocked.
+ * \note 1 maintenance blocked, 2 blocked in hardware.
+ * \note Set by user and link.
+ */
+ unsigned int locallyblocked:2;
+
+ /*!
+ * \brief Bitmask for the channel being remotely blocked.
+ * \note 1 maintenance blocked, 2 blocked in hardware.
+ * \note Set by user and link.
+ */
+ unsigned int remotelyblocked:2;
char context[AST_MAX_CONTEXT];
char mohinterpret[MAX_MUSICCLASS];
@@ -215,7 +252,15 @@ struct sig_ss7_chan {
char gen_add_number[50];
char gen_dig_number[50];
char orig_called_num[50];
+ int orig_called_presentation;
char redirecting_num[50];
+ int redirecting_presentation;
+ unsigned char redirect_counter;
+ unsigned char redirect_info;
+ unsigned char redirect_info_ind;
+ unsigned char redirect_info_orig_reas;
+ unsigned char redirect_info_counter;
+ unsigned char redirect_info_reas;
char generic_name[50];
unsigned char gen_add_num_plan;
unsigned char gen_add_nai;
@@ -233,22 +278,41 @@ struct sig_ss7_chan {
unsigned int call_ref_ident;
unsigned int call_ref_pc;
unsigned char calling_party_cat;
+ unsigned int do_hangup; /* What we have to do to clear the call */
+ unsigned int echocontrol_ind;
/*
* Channel status bits.
*/
- /*! TRUE if channel is associated with a link that is down. */
+ /*! \brief TRUE if channel is associated with a link that is down. */
unsigned int inalarm:1;
- /*! TRUE if this channel is being used for an outgoing call. */
+ /*! \brief TRUE if channel is in service. */
+ unsigned int inservice:1;
+ /*! \brief TRUE if this channel is being used for an outgoing call. */
unsigned int outgoing:1;
+ /*! \brief TRUE if the channel has completed collecting digits. */
+ unsigned int called_complete:1;
/*! \brief TRUE if the call has seen inband-information progress through the network. */
unsigned int progress:1;
- /*! \brief TRUE if the call has already gone/hungup */
- unsigned int alreadyhungup:1;
/*! \brief XXX BOOLEAN Purpose??? */
unsigned int rlt:1;
- /*! TRUE if this channel is in loopback. */
+ /*! \brief TRUE if this channel is in loopback. */
unsigned int loopedback:1;
+
+ /*
+ * Closed User Group fields Q.735.1
+ */
+ /*! \brief Network Identify Code as per Q.763 3.15.a */
+ char cug_interlock_ni[5];
+ /*! \brief Binari Code to uniquely identify a CUG inside the network. */
+ unsigned short cug_interlock_code;
+ /*!
+ * \brief Indication of the call being a CUG call and its permissions.
+ * \note 0 or 1 - non-CUG call
+ * \note 2 - CUG call, outgoing access alowed
+ * \note 3 - CUG call, outgoing access not alowed
+ */
+ unsigned char cug_indicator;
};
struct sig_ss7_linkset {
@@ -276,6 +340,7 @@ struct sig_ss7_linkset {
char nationalprefix[10]; /*!< area access code ('0' for european dialplans) */
char subscriberprefix[20]; /*!< area access code + area code ('0'+area code for european dialplans) */
char unknownprefix[20]; /*!< for unknown dialplans */
+ char networkroutedprefix[20];
};
void sig_ss7_set_alarm(struct sig_ss7_chan *p, int in_alarm);
@@ -284,12 +349,19 @@ void *ss7_linkset(void *data);
void sig_ss7_link_alarm(struct sig_ss7_linkset *linkset, int which);
void sig_ss7_link_noalarm(struct sig_ss7_linkset *linkset, int which);
-int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode);
+int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode, int cur_slc);
+
+int sig_ss7_reset_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc);
+int sig_ss7_reset_group(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, int range);
+int sig_ss7_cic_blocking(struct sig_ss7_linkset *linkset, int do_block, int cic);
+int sig_ss7_group_blocking(struct sig_ss7_linkset *linkset, int do_block, int startcic, int endcic, unsigned char state[], int type);
int sig_ss7_available(struct sig_ss7_chan *p);
int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rdest);
int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast);
int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast);
+int sig_ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc);
+int sig_ss7_find_cic_range(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc);
void sig_ss7_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_ss7_chan *pchan);
int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen);
struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law,
@@ -298,10 +370,14 @@ struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law
void sig_ss7_chan_delete(struct sig_ss7_chan *doomed);
struct sig_ss7_chan *sig_ss7_chan_new(void *pvt_data, struct sig_ss7_linkset *ss7);
void sig_ss7_init_linkset(struct sig_ss7_linkset *ss7);
+void sig_ss7_free_isup_call(struct sig_ss7_linkset *linkset, int channel);
void sig_ss7_cli_show_channels_header(int fd);
void sig_ss7_cli_show_channels(int fd, struct sig_ss7_linkset *linkset);
+int sig_ss7_cb_hangup(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup);
+void sig_ss7_cb_call_null(struct ss7 *ss7, struct isup_call *c, int lock);
+void sig_ss7_cb_notinservice(struct ss7 *ss7, int cic, unsigned int dpc);
/* ------------------------------------------------------------------- */
diff --git a/configs/chan_dahdi.conf.sample b/configs/chan_dahdi.conf.sample
index 83701ef00..2c0488aec 100644
--- a/configs/chan_dahdi.conf.sample
+++ b/configs/chan_dahdi.conf.sample
@@ -1371,12 +1371,35 @@ pickupgroup=1
; This option is used to disable automatic sending of ACM when the call is started
; in the dialplan. If you do use this option, you will need to use the Proceeding()
-; application in the dialplan to send ACM.
-;ss7_explictacm=yes
+; application in the dialplan to send ACM or enable ss7_autoacm below.
+;ss7_explicitacm=yes
+
+; Use this option to automatically send ACM when the call rings or is answered and
+; has not seen proceeding yet. If you use this option, you should disable ss7_explicitacm.
+; You may still use Proceeding() to explicitly send an ACM from the dialplan.
+;ss7_autoacm=yes
+
+; Create the linkset with all CICs in hardware remotely blocked state.
+;ss7_initialhwblo=yes
+
+; This option is whether or not to trust the remote echo control indication. This means
+; that in cases where echo control is reported by the remote end, we will trust them and
+; not enable echo cancellation on the call.
+;ss7_use_echocontrol=yes
+
+; This option is to set what our echo control indication is to the other end. Set to
+; yes to indicate that we are using echo cancellation or no if we are not.
+;ss7_default_echocontrol=yes
; All settings apply to linkset 1
;linkset = 1
+; Set the Signaling Link Code (SLC) for each sigchan.
+; If you manually set any you need to manually set all.
+; Should be defined before sigchan.
+; The default SLC starts with zero and increases for each defined sigchan.
+;slc=
+
; Point code of the linkset. For ITU, this is the decimal number
; format of the point code. For ANSI, this can either be in decimal
; number format or in the xxx-xxx-xxx format
@@ -1410,6 +1433,30 @@ pickupgroup=1
; Channels to associate with CICs on this linkset
;channel = 25-47
;
+
+; Set this option if you wish to send an Information Request Message (INR) request
+; if no calling party number is specified. This will attempt to tell the other end
+; to send it anyways. Should be defined after sigchan.
+;inr_if_no_calling=yes
+
+; Set this to set whether or not the originating access is (non) ISDN in the forward and
+; backward call indicators. Should be defined after sigchan
+;non_isdn_access=yes
+
+; This sets the number of binary places to shift the CIC when doing load balancing between
+; sigchans on a linkset. Should be defined after sigchan. Default 0
+;sls_shift = 0
+
+; Send custom cause_location value
+; Should be defined after sigchan. Default 1 (private local)
+;cause_location=1
+
+; SS7 timers (ISUP and MTP3) should be explicitly defined for each linkset to be used.
+; For a full list of supported timers and their default values (applicable for both ITU
+; and ANSI) see ss7.timers
+; Should be defined after sigchan
+;#include ss7.timers
+
; For more information on setting up SS7, see the README file in libss7 or
; https://wiki.asterisk.org/wiki/display/AST/Signaling+System+Number+7
; ----------------- SS7 Options ----------------------------------------
diff --git a/configs/ss7.timers.sample b/configs/ss7.timers.sample
new file mode 100644
index 000000000..9cf9bd1ab
--- /dev/null
+++ b/configs/ss7.timers.sample
@@ -0,0 +1,65 @@
+;;;;; ITU-T Q.707 timers
+
+;mtp3_timer.q707_t1 = 4000
+;mtp3_timer.q707_t2 = 30000
+
+;;;;; MTP3 timers as specified in ITU-T Q.704 or ANSI T1.111-2001
+
+mtp3_timer.t1 = 500
+mtp3_timer.t2 = 700
+mtp3_timer.t3 = 500
+mtp3_timer.t4 = 500
+mtp3_timer.t5 = 500
+mtp3_timer.t6 = 500
+mtp3_timer.t7 = 1000
+
+mtp3_timer.t10 = 60000
+
+mtp3_timer.t12 = 800
+mtp3_timer.t13 = 800
+mtp3_timer.t14 = 2000
+
+; enable for ITU only. Timers after T17 are defined differently for ANSI
+;mtp3_timer.t19 = 67000
+;mtp3_timer.t21 = 63000
+;
+;mtp3_timer.t22 = 300000
+;mtp3_timer.t23 = 300000
+
+
+;;;;; ISUP timers as specified in ITU-T Q.764 or ANSI T1.113-2000
+
+isup_timer.t1 = 15000
+;isup_timer.t2 = 180000 ; ITU only
+
+;isup_timer.t5 = 300000 ; for ITU
+;isup_timer.t5 = 60000 ; for ANSI
+isup_timer.t6 = 30000
+isup_timer.t7 = 20000
+isup_timer.t8 = 10000
+
+;isup_timer.t10 = 4000 ; ITU only
+
+isup_timer.t12 = 15000
+;isup_timer.t13 = 300000 ; for ITU
+;isup_timer.t13 = 60000 ; for ANSI
+isup_timer.t14 = 15000
+;isup_timer.t15 = 300000 ; for ITU
+;isup_timer.t15 = 60000 ; for ANSI
+isup_timer.t16 = 15000
+;isup_timer.t17 = 300000 ; for ITU
+;isup_timer.t17 = 60000 ; for ANSI
+isup_timer.t18 = 15000
+;isup_timer.t19 = 300000 ; for ITU
+;isup_timer.t19 = 60000 ; for ANSI
+isup_timer.t20 = 15000
+;isup_timer.t21 = 300000 ; for ITU
+;isup_timer.t21 = 60000 ; for ANSI
+isup_timer.t22 = 15000
+;isup_timer.t23 = 300000 ; for ITU
+;isup_timer.t23 = 60000 ; for ANSI
+
+isup_timer.t27 = 240000
+
+isup_timer.t33 = 12000
+;isup_timer.t35 = 15000 ; ITU only
diff --git a/configure b/configure
index a02817025..59d48c6c1 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.ac Revision: 412977 .
+# From configure.ac Revision: 413772 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.68 for asterisk trunk.
#
@@ -26664,7 +26664,7 @@ fi
fi
-# Check for libss7 v1.0 branch compatible version.
+# Check for libss7 v2.0 branch compatible version.
if test "x${PBX_SS7}" != "x1" -a "${USE_SS7}" != "no"; then
pbxlibdir=""
@@ -26676,7 +26676,7 @@ if test "x${PBX_SS7}" != "x1" -a "${USE_SS7}" != "no"; then
pbxlibdir="-L${SS7_DIR}"
fi
fi
- pbxfuncname="ss7_set_adjpc"
+ pbxfuncname="ss7_set_isup_timer"
if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers
AST_SS7_FOUND=yes
else
diff --git a/configure.ac b/configure.ac
index da9d2d751..95b7dd02b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2096,8 +2096,8 @@ if test "x${PBX_SPANDSP}" = "x1" ; then
AST_EXT_LIB_CHECK([SPANDSP], [spandsp], [t38_terminal_init], [spandsp.h], [-ltiff])
fi
-# Check for libss7 v1.0 branch compatible version.
-AST_EXT_LIB_CHECK([SS7], [ss7], [ss7_set_adjpc], [libss7.h])
+# Check for libss7 v2.0 branch compatible version.
+AST_EXT_LIB_CHECK([SS7], [ss7], [ss7_set_isup_timer], [libss7.h])
AST_EXT_LIB_CHECK([OPENR2], [openr2], [openr2_chan_new], [openr2.h])