|
|
|
@ -762,6 +762,7 @@ struct dahdi_mfcr2 {
|
|
|
|
|
openr2_context_t *protocol_context; /*!< OpenR2 context handle */
|
|
|
|
|
struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS]; /*!< Member channel pvt structs */
|
|
|
|
|
int numchans; /*!< Number of channels in this R2 block */
|
|
|
|
|
int live_chans; /*!< Number of unremoved channels in this R2 block */
|
|
|
|
|
int nodev; /*!< Link disconnected? */
|
|
|
|
|
struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
|
|
|
|
|
};
|
|
|
|
@ -771,6 +772,8 @@ struct r2link_entry {
|
|
|
|
|
AST_LIST_ENTRY(r2link_entry) list;
|
|
|
|
|
};
|
|
|
|
|
static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
|
|
|
|
|
static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* how many r2links have been malloc'd */
|
|
|
|
|
static int r2links_count = 0;
|
|
|
|
@ -3615,6 +3618,21 @@ static void handle_clear_alarms(struct dahdi_pvt *p)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_OPENR2
|
|
|
|
|
static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
|
|
|
|
|
{
|
|
|
|
|
const struct dahdi_mfcr2 *r2link = p->mfcr2;
|
|
|
|
|
struct r2link_entry *cur;
|
|
|
|
|
AST_LIST_LOCK(&r2links);
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
|
|
|
|
if (r2link == &cur->mfcr2) {
|
|
|
|
|
ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
|
|
|
|
|
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
|
|
|
|
AST_LIST_UNLOCK(&r2links);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dahdi_r2_answer(struct dahdi_pvt *p)
|
|
|
|
|
{
|
|
|
|
@ -3700,6 +3718,9 @@ static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
|
|
|
|
|
p->inalarm = alarm ? 1 : 0;
|
|
|
|
|
if (p->inalarm) {
|
|
|
|
|
res = get_alarms(p);
|
|
|
|
|
if (res == DAHDI_ALARM_NOTOPEN) {
|
|
|
|
|
mfcr2_queue_for_destruction(p);
|
|
|
|
|
}
|
|
|
|
|
handle_alarms(p, res);
|
|
|
|
|
} else {
|
|
|
|
|
handle_clear_alarms(p);
|
|
|
|
@ -5557,6 +5578,49 @@ static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
|
|
|
|
|
}
|
|
|
|
|
#endif /* defined(HAVE_SS7) */
|
|
|
|
|
|
|
|
|
|
#if defined(HAVE_OPENR2)
|
|
|
|
|
/*!
|
|
|
|
|
* \internal
|
|
|
|
|
* \brief Unlink the channel interface from the MFC/R2 private pointer array.
|
|
|
|
|
*
|
|
|
|
|
* \param pvt chan_dahdi private interface structure to unlink.
|
|
|
|
|
*
|
|
|
|
|
* \return Nothing
|
|
|
|
|
*/
|
|
|
|
|
static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
struct dahdi_mfcr2 *mfcr2;
|
|
|
|
|
int should_destroy_link = 0;
|
|
|
|
|
|
|
|
|
|
ast_mutex_lock(&pvt->lock);
|
|
|
|
|
if (pvt->r2chan) {
|
|
|
|
|
ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
|
|
|
|
|
openr2_chan_disable_read(pvt->r2chan);
|
|
|
|
|
}
|
|
|
|
|
mfcr2 = pvt->mfcr2;
|
|
|
|
|
if (mfcr2) {
|
|
|
|
|
for (idx = 0; idx < mfcr2->numchans; ++idx) {
|
|
|
|
|
if (mfcr2->pvts[idx] == pvt) {
|
|
|
|
|
ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
|
|
|
|
|
mfcr2->pvts[idx] = NULL;
|
|
|
|
|
mfcr2->live_chans--;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!mfcr2->live_chans) {
|
|
|
|
|
ast_debug(1, "MFC/R2 link is now empty\n");
|
|
|
|
|
should_destroy_link = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&pvt->lock);
|
|
|
|
|
if (should_destroy_link) {
|
|
|
|
|
ast_debug(1, "MFC/R2 link is now empty\n");
|
|
|
|
|
mfcr2_queue_for_destruction(pvt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* defined(HAVE_OPENR2) */
|
|
|
|
|
|
|
|
|
|
static struct dahdi_pvt *find_next_iface_in_span(struct dahdi_pvt *cur)
|
|
|
|
|
{
|
|
|
|
|
if (cur->next && cur->next->span == cur->span) {
|
|
|
|
@ -5585,6 +5649,9 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
|
|
|
|
|
#endif /* defined(HAVE_PRI) */
|
|
|
|
|
#if defined(HAVE_SS7)
|
|
|
|
|
dahdi_unlink_ss7_pvt(p);
|
|
|
|
|
#endif /* defined(HAVE_SS7) */
|
|
|
|
|
#if defined(HAVE_OPENR2)
|
|
|
|
|
dahdi_unlink_mfcr2_pvt(p);
|
|
|
|
|
#endif /* defined(HAVE_SS7) */
|
|
|
|
|
switch (pvt->which_iflist) {
|
|
|
|
|
case DAHDI_IFLIST_NONE:
|
|
|
|
@ -11099,6 +11166,40 @@ static void dahdi_destroy_channel_range(int start, int end)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_OPENR2
|
|
|
|
|
static void dahdi_r2_destroy_nodev(void)
|
|
|
|
|
{
|
|
|
|
|
struct r2link_entry *cur;
|
|
|
|
|
AST_LIST_LOCK(&nodev_r2links);
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
|
|
|
|
|
int i;
|
|
|
|
|
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
|
|
|
|
|
ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
|
|
|
|
|
for (i = 0; i < r2->numchans; i++) {
|
|
|
|
|
int channel;
|
|
|
|
|
struct dahdi_pvt *pvt = r2->pvts[i];
|
|
|
|
|
if (!pvt) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
channel = pvt->channel;
|
|
|
|
|
ast_debug(3, "About to destroy B-channel %d.\n", channel);
|
|
|
|
|
dahdi_destroy_channel_range(channel, channel);
|
|
|
|
|
}
|
|
|
|
|
ast_debug(3, "Destroying R2 link\n");
|
|
|
|
|
AST_LIST_REMOVE(&nodev_r2links, cur, list);
|
|
|
|
|
if (r2->r2master != AST_PTHREADT_NULL) {
|
|
|
|
|
pthread_cancel(r2->r2master);
|
|
|
|
|
pthread_join(r2->r2master, NULL);
|
|
|
|
|
r2->r2master = AST_PTHREADT_NULL;
|
|
|
|
|
openr2_context_delete(r2->protocol_context);
|
|
|
|
|
}
|
|
|
|
|
ast_free(cur);
|
|
|
|
|
}
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
|
|
|
|
AST_LIST_UNLOCK(&nodev_r2links);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static int setup_dahdi(int reload);
|
|
|
|
|
static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
|
|
|
|
|
|
|
|
|
@ -11722,6 +11823,9 @@ static void *do_monitor(void *data)
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&iflock);
|
|
|
|
|
release_doomed_pris();
|
|
|
|
|
#ifdef HAVE_OPENR2
|
|
|
|
|
dahdi_r2_destroy_nodev();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
/* Never reached */
|
|
|
|
|
pthread_cleanup_pop(1);
|
|
|
|
@ -11908,21 +12012,17 @@ static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
|
|
|
|
|
static void dahdi_r2_destroy_links(void)
|
|
|
|
|
{
|
|
|
|
|
struct r2link_entry *cur;
|
|
|
|
|
|
|
|
|
|
/* Queue everything for removal */
|
|
|
|
|
AST_LIST_LOCK(&r2links);
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
|
|
|
|
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
|
|
|
|
|
ast_debug(3, "Destroying R2 link\n");
|
|
|
|
|
AST_LIST_REMOVE(&r2links, cur, list);
|
|
|
|
|
if (r2->r2master != AST_PTHREADT_NULL) {
|
|
|
|
|
pthread_cancel(r2->r2master);
|
|
|
|
|
pthread_join(r2->r2master, NULL);
|
|
|
|
|
openr2_context_delete(r2->protocol_context);
|
|
|
|
|
}
|
|
|
|
|
ast_free(cur);
|
|
|
|
|
ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
|
|
|
|
|
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
|
|
|
|
}
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
|
|
|
|
AST_LIST_UNLOCK(&r2links);
|
|
|
|
|
r2links_count = 0;
|
|
|
|
|
/* Now destroy properly */
|
|
|
|
|
dahdi_r2_destroy_nodev();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
|
|
|
|
@ -12288,6 +12388,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|
|
|
|
destroy_dahdi_pvt(tmp);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
r2_link->live_chans++;
|
|
|
|
|
tmp->mfcr2 = r2_link;
|
|
|
|
|
if (conf->mfcr2.call_files) {
|
|
|
|
|
openr2_chan_enable_call_files(tmp->r2chan);
|
|
|
|
@ -13853,6 +13954,8 @@ static void dahdi_ss7_error(struct ss7 *ss7, char *s)
|
|
|
|
|
static void *mfcr2_monitor(void *data)
|
|
|
|
|
{
|
|
|
|
|
struct dahdi_mfcr2 *mfcr2 = data;
|
|
|
|
|
struct dahdi_pvt *pvt;
|
|
|
|
|
|
|
|
|
|
/* we should be using pthread_key_create
|
|
|
|
|
and allocate pollers dynamically.
|
|
|
|
|
I think do_monitor() could be leaking, since it
|
|
|
|
@ -13869,8 +13972,12 @@ static void *mfcr2_monitor(void *data)
|
|
|
|
|
/* now that we're ready to get calls, unblock our side and
|
|
|
|
|
get current line state */
|
|
|
|
|
for (i = 0; i < mfcr2->numchans; i++) {
|
|
|
|
|
openr2_chan_set_idle(mfcr2->pvts[i]->r2chan);
|
|
|
|
|
openr2_chan_handle_cas(mfcr2->pvts[i]->r2chan);
|
|
|
|
|
pvt = mfcr2->pvts[i];
|
|
|
|
|
if (!pvt) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
openr2_chan_set_idle(pvt->r2chan);
|
|
|
|
|
openr2_chan_handle_cas(pvt->r2chan);
|
|
|
|
|
}
|
|
|
|
|
while (1) {
|
|
|
|
|
/* we trust here that the mfcr2 channel list will not ever change once
|
|
|
|
@ -13879,20 +13986,24 @@ static void *mfcr2_monitor(void *data)
|
|
|
|
|
for (i = 0; i < mfcr2->numchans; i++) {
|
|
|
|
|
pollers[i].revents = 0;
|
|
|
|
|
pollers[i].events = 0;
|
|
|
|
|
if (mfcr2->pvts[i]->owner) {
|
|
|
|
|
pvt = mfcr2->pvts[i];
|
|
|
|
|
if (!pvt) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (pvt->owner) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (mfcr2->nodev) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!mfcr2->pvts[i]->r2chan) {
|
|
|
|
|
ast_debug(1, "Wow, no r2chan on channel %d\n", mfcr2->pvts[i]->channel);
|
|
|
|
|
if (!pvt->r2chan) {
|
|
|
|
|
ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
|
|
|
|
|
quit_loop = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
openr2_chan_enable_read(mfcr2->pvts[i]->r2chan);
|
|
|
|
|
openr2_chan_enable_read(pvt->r2chan);
|
|
|
|
|
pollers[i].events = POLLIN | POLLPRI;
|
|
|
|
|
pollers[i].fd = mfcr2->pvts[i]->subs[SUB_REAL].dfd;
|
|
|
|
|
pollers[i].fd = pvt->subs[SUB_REAL].dfd;
|
|
|
|
|
pollsize++;
|
|
|
|
|
}
|
|
|
|
|
if (quit_loop) {
|
|
|
|
@ -13919,8 +14030,12 @@ static void *mfcr2_monitor(void *data)
|
|
|
|
|
/* do we want to allow to cancel while processing events? */
|
|
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
|
|
|
|
for (i = 0; i < mfcr2->numchans; i++) {
|
|
|
|
|
pvt = mfcr2->pvts[i];
|
|
|
|
|
if (!pvt) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
|
|
|
|
|
openr2_chan_process_event(mfcr2->pvts[i]->r2chan);
|
|
|
|
|
openr2_chan_process_event(pvt->r2chan);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
|
|
|
|
@ -15224,6 +15339,51 @@ static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct as
|
|
|
|
|
return CLI_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
int wanted_link_index;
|
|
|
|
|
int found_link = 0;
|
|
|
|
|
struct r2link_entry *cur = NULL;
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case CLI_INIT:
|
|
|
|
|
e->command = "mfcr2 destroy link";
|
|
|
|
|
e->usage =
|
|
|
|
|
"Usage: mfcr2 destroy link <index-number>\n"
|
|
|
|
|
" Destorys D-channel of link and its B-channels.\n"
|
|
|
|
|
" DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
|
|
|
|
|
return NULL;
|
|
|
|
|
case CLI_GENERATE:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (a->argc < 4) {
|
|
|
|
|
return CLI_SHOWUSAGE;
|
|
|
|
|
}
|
|
|
|
|
res = sscanf(a->argv[3], "%30d", &wanted_link_index);
|
|
|
|
|
if ((res != 1) || wanted_link_index < 1) {
|
|
|
|
|
ast_cli(a->fd,
|
|
|
|
|
"Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
|
|
|
|
|
return CLI_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
AST_LIST_LOCK(&r2links);
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
|
|
|
|
struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
|
|
|
|
|
if (wanted_link_index == mfcr2->index) {
|
|
|
|
|
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
|
|
|
|
r2links_count--;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
|
|
|
|
AST_LIST_UNLOCK(&r2links);
|
|
|
|
|
if (! found_link) {
|
|
|
|
|
ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
|
|
|
|
|
return CLI_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
return CLI_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct ast_cli_entry dahdi_mfcr2_cli[] = {
|
|
|
|
|
AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
|
|
|
|
|
AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
|
|
|
|
@ -15233,6 +15393,7 @@ static struct ast_cli_entry dahdi_mfcr2_cli[] = {
|
|
|
|
|
AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
|
|
|
|
|
AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
|
|
|
|
|
AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
|
|
|
|
|
AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif /* HAVE_OPENR2 */
|
|
|
|
@ -19568,13 +19729,15 @@ static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, str
|
|
|
|
|
AST_LIST_LOCK(&r2links);
|
|
|
|
|
AST_LIST_TRAVERSE(&r2links, cur, list) {
|
|
|
|
|
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
|
|
|
|
|
if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
|
|
|
|
|
if (r2->r2master == AST_PTHREADT_NULL) {
|
|
|
|
|
if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
|
|
|
|
|
}
|
|
|
|
|
x++;
|
|
|
|
|
}
|
|
|
|
|
x++;
|
|
|
|
|
}
|
|
|
|
|
AST_LIST_UNLOCK(&r2links);
|
|
|
|
|
}
|
|
|
|
|