Newer
Older
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2009, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
* \brief PRI signaling module
*
* \author Matthew Fredrickson <creslin@digium.com>
*/
/*** MODULEINFO
<support_level>core</support_level>
***/
#include "asterisk.h"
#ifdef HAVE_PRI
#include <errno.h>
#include <ctype.h>
#include <signal.h>
#include "asterisk/utils.h"
#include "asterisk/options.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/say.h"
#include "asterisk/manager.h"
#include "asterisk/astdb.h"
#include "asterisk/causes.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/transcap.h"
#include "asterisk/features.h"
#include "sig_pri.h"
#ifndef PRI_EVENT_FACILITY
#error "Upgrade your libpri"
#endif
Matthew Jordan
committed
/*** DOCUMENTATION
***/
/* define this to send PRI user-user information elements */
#undef SUPPORT_USERUSER
/*!
* Define to make always pick a channel if allowed. Useful for
* testing channel shifting.
*/
//#define ALWAYS_PICK_CHANNEL 1
/*!
* Define to force a RESTART on a channel that returns a cause
* code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44). If the cause
* is because of a stuck channel on the peer and the channel is
* always the next channel we pick for an outgoing call then
* this can help.
*/
#define FORCE_RESTART_UNAVAIL_CHANS 1
#if defined(HAVE_PRI_CCSS)
struct sig_pri_cc_agent_prv {
/*! Asterisk span D channel control structure. */
struct sig_pri_span *pri;
/*! CC id value to use with libpri. -1 if invalid. */
long cc_id;
/*! TRUE if CC has been requested and we are waiting for the response. */
unsigned char cc_request_response_pending;
};
struct sig_pri_cc_monitor_instance {
/*! \brief Asterisk span D channel control structure. */
struct sig_pri_span *pri;
/*! CC id value to use with libpri. (-1 if already canceled). */
long cc_id;
/*! CC core id value. */
int core_id;
/*! Device name(Channel name less sequence number) */
char name[1];
};
/*! Upper level agent/monitor type name. */
static const char *sig_pri_cc_type_name;
/*! Container of sig_pri monitor instances. */
static struct ao2_container *sig_pri_cc_monitors;
#endif /* defined(HAVE_PRI_CCSS) */
static int pri_matchdigittimeout = 3000;
static int pri_gendigittimeout = 8000;
#define DCHAN_NOTINALARM (1 << 0)
#define DCHAN_UP (1 << 1)
Richard Mudgett
committed
/* Defines to help decode the encoded event channel id. */
#define PRI_CHANNEL(p) ((p) & 0xff)
#define PRI_SPAN(p) (((p) >> 8) & 0xff)
#define PRI_EXPLICIT (1 << 16)
#define PRI_CIS_CALL (1 << 17) /* Call is using the D channel only. */
#define PRI_HELD_CALL (1 << 18)
#define DCHAN_AVAILABLE (DCHAN_NOTINALARM | DCHAN_UP)
static int pri_active_dchan_index(struct sig_pri_span *pri);
static const char *sig_pri_call_level2str(enum sig_pri_call_level level)
{
switch (level) {
case SIG_PRI_CALL_LEVEL_IDLE:
return "Idle";
case SIG_PRI_CALL_LEVEL_SETUP:
return "Setup";
case SIG_PRI_CALL_LEVEL_OVERLAP:
return "Overlap";
case SIG_PRI_CALL_LEVEL_PROCEEDING:
return "Proceeding";
case SIG_PRI_CALL_LEVEL_ALERTING:
return "Alerting";
case SIG_PRI_CALL_LEVEL_DEFER_DIAL:
return "DeferDial";
case SIG_PRI_CALL_LEVEL_CONNECT:
return "Connect";
}
return "Unknown";
}
static inline void pri_rel(struct sig_pri_span *pri)
{
ast_mutex_unlock(&pri->lock);
}
static unsigned int PVT_TO_CHANNEL(struct sig_pri_chan *p)
{
Richard Mudgett
committed
int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? PRI_EXPLICIT : 0));
ast_debug(5, "prioffset: %d mastertrunkgroup: %d logicalspan: %d result: %d\n",
p->prioffset, p->mastertrunkgroup, p->logicalspan, res);
return res;
static void sig_pri_handle_dchan_exception(struct sig_pri_span *pri, int index)
if (sig_pri_callbacks.handle_dchan_exception) {
sig_pri_callbacks.handle_dchan_exception(pri, index);
}
Richard Mudgett
committed
static void sig_pri_set_dialing(struct sig_pri_chan *p, int is_dialing)
if (sig_pri_callbacks.set_dialing) {
sig_pri_callbacks.set_dialing(p->chan_pvt, is_dialing);
Richard Mudgett
committed
}
Richard Mudgett
committed
static void sig_pri_set_digital(struct sig_pri_chan *p, int is_digital)
Richard Mudgett
committed
p->digital = is_digital;
if (sig_pri_callbacks.set_digital) {
sig_pri_callbacks.set_digital(p->chan_pvt, is_digital);
Richard Mudgett
committed
}
}
static void sig_pri_set_outgoing(struct sig_pri_chan *p, int is_outgoing)
{
p->outgoing = is_outgoing;
if (sig_pri_callbacks.set_outgoing) {
sig_pri_callbacks.set_outgoing(p->chan_pvt, is_outgoing);
void sig_pri_set_alarm(struct sig_pri_chan *p, int in_alarm)
Richard Mudgett
committed
{
if (sig_pri_is_alarm_ignored(p->pri)) {
/* Always set not in alarm */
in_alarm = 0;
}
* Clear the channel restart state when the channel alarm
* changes to prevent the state from getting stuck when the link
* goes down.
p->resetting = SIG_PRI_RESET_IDLE;
Richard Mudgett
committed
p->inalarm = in_alarm;
if (sig_pri_callbacks.set_alarm) {
sig_pri_callbacks.set_alarm(p->chan_pvt, in_alarm);
Richard Mudgett
committed
}
static const char *sig_pri_get_orig_dialstring(struct sig_pri_chan *p)
{
if (sig_pri_callbacks.get_orig_dialstring) {
return sig_pri_callbacks.get_orig_dialstring(p->chan_pvt);
}
ast_log(LOG_ERROR, "get_orig_dialstring callback not defined\n");
return "";
}
#if defined(HAVE_PRI_CCSS)
static void sig_pri_make_cc_dialstring(struct sig_pri_chan *p, char *buf, size_t buf_size)
{
if (sig_pri_callbacks.make_cc_dialstring) {
sig_pri_callbacks.make_cc_dialstring(p->chan_pvt, buf, buf_size);
} else {
ast_log(LOG_ERROR, "make_cc_dialstring callback not defined\n");
buf[0] = '\0';
}
}
#endif /* defined(HAVE_PRI_CCSS) */
static void sig_pri_dial_digits(struct sig_pri_chan *p, const char *dial_string)
{
if (sig_pri_callbacks.dial_digits) {
sig_pri_callbacks.dial_digits(p->chan_pvt, dial_string);
}
}
/*!
* \internal
* \brief Reevaluate the PRI span device state.
* \since 1.8
*
* \param pri PRI span control structure.
*
* \return Nothing
*
* \note Assumes the pri->lock is already obtained.
*/
static void sig_pri_span_devstate_changed(struct sig_pri_span *pri)
if (sig_pri_callbacks.update_span_devstate) {
sig_pri_callbacks.update_span_devstate(pri);
/*!
* \internal
* \brief Set the caller id information in the parent module.
Kevin P. Fleming
committed
* \since 1.8
*
* \param p sig_pri channel structure.
*
* \return Nothing
*/
static void sig_pri_set_caller_id(struct sig_pri_chan *p)
{
struct ast_party_caller caller;
if (sig_pri_callbacks.set_callerid) {
ast_party_caller_init(&caller);
caller.id.name.str = p->cid_name;
caller.id.name.presentation = p->callingpres;
caller.id.name.valid = 1;
caller.id.number.str = p->cid_num;
caller.id.number.plan = p->cid_ton;
caller.id.number.presentation = p->callingpres;
caller.id.number.valid = 1;
Richard Mudgett
committed
if (!ast_strlen_zero(p->cid_subaddr)) {
caller.id.subaddress.valid = 1;
//caller.id.subaddress.type = 0;/* nsap */
//caller.id.subaddress.odd_even_indicator = 0;
caller.id.subaddress.str = p->cid_subaddr;
}
caller.id.tag = p->user_tag;
caller.ani.number.str = p->cid_ani;
//caller.ani.number.plan = p->xxx;
//caller.ani.number.presentation = p->xxx;
caller.ani.number.valid = 1;
caller.ani2 = p->cid_ani2;
sig_pri_callbacks.set_callerid(p->chan_pvt, &caller);
}
}
/*!
* \internal
* \brief Set the Dialed Number Identifier.
Kevin P. Fleming
committed
* \since 1.8
*
* \param p sig_pri channel structure.
* \param dnid Dialed Number Identifier string.
*
* \return Nothing
*/
static void sig_pri_set_dnid(struct sig_pri_chan *p, const char *dnid)
{
if (sig_pri_callbacks.set_dnid) {
sig_pri_callbacks.set_dnid(p->chan_pvt, dnid);
}
}
/*!
* \internal
* \brief Set the Redirecting Directory Number Information Service (RDNIS).
Kevin P. Fleming
committed
* \since 1.8
*
* \param p sig_pri channel structure.
* \param rdnis Redirecting Directory Number Information Service (RDNIS) string.
*
* \return Nothing
*/
static void sig_pri_set_rdnis(struct sig_pri_chan *p, const char *rdnis)
{
if (sig_pri_callbacks.set_rdnis) {
sig_pri_callbacks.set_rdnis(p->chan_pvt, rdnis);
static void sig_pri_unlock_private(struct sig_pri_chan *p)
{
if (sig_pri_callbacks.unlock_private) {
sig_pri_callbacks.unlock_private(p->chan_pvt);
}
}
static void sig_pri_lock_private(struct sig_pri_chan *p)
{
if (sig_pri_callbacks.lock_private) {
sig_pri_callbacks.lock_private(p->chan_pvt);
}
static void sig_pri_deadlock_avoidance_private(struct sig_pri_chan *p)
{
if (sig_pri_callbacks.deadlock_avoidance_private) {
sig_pri_callbacks.deadlock_avoidance_private(p->chan_pvt);
} else {
/* Fallback to the old way if callback not present. */
Richard Mudgett
committed
sig_pri_unlock_private(p);
sched_yield();
sig_pri_lock_private(p);
}
}
static void pri_grab(struct sig_pri_chan *p, struct sig_pri_span *pri)
{
/* Grab the lock first */
Richard Mudgett
committed
while (ast_mutex_trylock(&pri->lock)) {
/* Avoid deadlock */
sig_pri_deadlock_avoidance_private(p);
}
/* Then break the poll */
Richard Mudgett
committed
if (pri->master != AST_PTHREADT_NULL) {
pthread_kill(pri->master, SIGURG);
}
/*!
* \internal
* \brief Convert PRI redirecting reason to asterisk version.
Kevin P. Fleming
committed
* \since 1.8
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
*
* \param pri_reason PRI redirecting reason.
*
* \return Equivalent asterisk redirecting reason value.
*/
static enum AST_REDIRECTING_REASON pri_to_ast_reason(int pri_reason)
{
enum AST_REDIRECTING_REASON ast_reason;
switch (pri_reason) {
case PRI_REDIR_FORWARD_ON_BUSY:
ast_reason = AST_REDIRECTING_REASON_USER_BUSY;
break;
case PRI_REDIR_FORWARD_ON_NO_REPLY:
ast_reason = AST_REDIRECTING_REASON_NO_ANSWER;
break;
case PRI_REDIR_DEFLECTION:
ast_reason = AST_REDIRECTING_REASON_DEFLECTION;
break;
case PRI_REDIR_UNCONDITIONAL:
ast_reason = AST_REDIRECTING_REASON_UNCONDITIONAL;
break;
case PRI_REDIR_UNKNOWN:
default:
ast_reason = AST_REDIRECTING_REASON_UNKNOWN;
break;
}
return ast_reason;
}
/*!
* \internal
* \brief Convert asterisk redirecting reason to PRI version.
Kevin P. Fleming
committed
* \since 1.8
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
*
* \param ast_reason Asterisk redirecting reason.
*
* \return Equivalent PRI redirecting reason value.
*/
static int ast_to_pri_reason(enum AST_REDIRECTING_REASON ast_reason)
{
int pri_reason;
switch (ast_reason) {
case AST_REDIRECTING_REASON_USER_BUSY:
pri_reason = PRI_REDIR_FORWARD_ON_BUSY;
break;
case AST_REDIRECTING_REASON_NO_ANSWER:
pri_reason = PRI_REDIR_FORWARD_ON_NO_REPLY;
break;
case AST_REDIRECTING_REASON_UNCONDITIONAL:
pri_reason = PRI_REDIR_UNCONDITIONAL;
break;
case AST_REDIRECTING_REASON_DEFLECTION:
pri_reason = PRI_REDIR_DEFLECTION;
break;
case AST_REDIRECTING_REASON_UNKNOWN:
default:
pri_reason = PRI_REDIR_UNKNOWN;
break;
}
return pri_reason;
}
/*!
* \internal
* \brief Convert PRI number presentation to asterisk version.
Kevin P. Fleming
committed
* \since 1.8
*
* \param pri_presentation PRI number presentation.
*
* \return Equivalent asterisk number presentation value.
*/
static int pri_to_ast_presentation(int pri_presentation)
{
int ast_presentation;
switch (pri_presentation) {
Richard Mudgett
committed
case PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED:
ast_presentation = AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED;
Richard Mudgett
committed
case PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_PASSED_SCREEN:
ast_presentation = AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN;
Richard Mudgett
committed
case PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_FAILED_SCREEN:
ast_presentation = AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN;
Richard Mudgett
committed
case PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER:
ast_presentation = AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER;
Richard Mudgett
committed
case PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED:
ast_presentation = AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
Richard Mudgett
committed
case PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_PASSED_SCREEN:
ast_presentation = AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN;
Richard Mudgett
committed
case PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_FAILED_SCREEN:
ast_presentation = AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN;
Richard Mudgett
committed
case PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER:
ast_presentation = AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER;
Richard Mudgett
committed
case PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED:
case PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_PASSED_SCREEN:
case PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_FAILED_SCREEN:
case PRI_PRES_UNAVAILABLE | PRI_PRES_NETWORK_NUMBER:
ast_presentation = AST_PRES_NUMBER_NOT_AVAILABLE;
break;
Richard Mudgett
committed
Richard Mudgett
committed
ast_presentation = AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
break;
}
return ast_presentation;
}
/*!
* \internal
* \brief Convert asterisk number presentation to PRI version.
Kevin P. Fleming
committed
* \since 1.8
*
* \param ast_presentation Asterisk number presentation.
*
* \return Equivalent PRI number presentation value.
*/
static int ast_to_pri_presentation(int ast_presentation)
{
int pri_presentation;
switch (ast_presentation) {
Richard Mudgett
committed
case AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED:
pri_presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
Richard Mudgett
committed
case AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN:
pri_presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_PASSED_SCREEN;
Richard Mudgett
committed
case AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN:
pri_presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_FAILED_SCREEN;
Richard Mudgett
committed
case AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER:
pri_presentation = PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER;
Richard Mudgett
committed
case AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED:
pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
Richard Mudgett
committed
case AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN:
pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_PASSED_SCREEN;
Richard Mudgett
committed
case AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN:
pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_FAILED_SCREEN;
Richard Mudgett
committed
case AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER:
pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER;
Richard Mudgett
committed
case AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED:
case AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_PASSED_SCREEN:
case AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_FAILED_SCREEN:
case AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER:
pri_presentation = PRES_NUMBER_NOT_AVAILABLE;
break;
Richard Mudgett
committed
Richard Mudgett
committed
pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
break;
}
return pri_presentation;
}
/*!
* \internal
* \brief Convert PRI name char_set to asterisk version.
Kevin P. Fleming
committed
* \since 1.8
* \return Equivalent asterisk name char_set value.
static enum AST_PARTY_CHAR_SET pri_to_ast_char_set(int pri_char_set)
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
switch (pri_char_set) {
default:
case PRI_CHAR_SET_UNKNOWN:
ast_char_set = AST_PARTY_CHAR_SET_UNKNOWN;
break;
case PRI_CHAR_SET_ISO8859_1:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_1;
break;
case PRI_CHAR_SET_WITHDRAWN:
ast_char_set = AST_PARTY_CHAR_SET_WITHDRAWN;
break;
case PRI_CHAR_SET_ISO8859_2:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_2;
break;
case PRI_CHAR_SET_ISO8859_3:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_3;
break;
case PRI_CHAR_SET_ISO8859_4:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_4;
break;
case PRI_CHAR_SET_ISO8859_5:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_5;
break;
case PRI_CHAR_SET_ISO8859_7:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_7;
break;
case PRI_CHAR_SET_ISO10646_BMPSTRING:
ast_char_set = AST_PARTY_CHAR_SET_ISO10646_BMPSTRING;
break;
case PRI_CHAR_SET_ISO10646_UTF_8STRING:
ast_char_set = AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING;
break;
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
return ast_char_set;
}
/*!
* \internal
* \brief Convert asterisk name char_set to PRI version.
* \since 1.8
*
* \param ast_char_set Asterisk name char_set.
*
* \return Equivalent PRI name char_set value.
*/
static int ast_to_pri_char_set(enum AST_PARTY_CHAR_SET ast_char_set)
{
int pri_char_set;
switch (ast_char_set) {
default:
case AST_PARTY_CHAR_SET_UNKNOWN:
pri_char_set = PRI_CHAR_SET_UNKNOWN;
break;
case AST_PARTY_CHAR_SET_ISO8859_1:
pri_char_set = PRI_CHAR_SET_ISO8859_1;
break;
case AST_PARTY_CHAR_SET_WITHDRAWN:
pri_char_set = PRI_CHAR_SET_WITHDRAWN;
break;
case AST_PARTY_CHAR_SET_ISO8859_2:
pri_char_set = PRI_CHAR_SET_ISO8859_2;
break;
case AST_PARTY_CHAR_SET_ISO8859_3:
pri_char_set = PRI_CHAR_SET_ISO8859_3;
break;
case AST_PARTY_CHAR_SET_ISO8859_4:
pri_char_set = PRI_CHAR_SET_ISO8859_4;
break;
case AST_PARTY_CHAR_SET_ISO8859_5:
pri_char_set = PRI_CHAR_SET_ISO8859_5;
break;
case AST_PARTY_CHAR_SET_ISO8859_7:
pri_char_set = PRI_CHAR_SET_ISO8859_7;
break;
case AST_PARTY_CHAR_SET_ISO10646_BMPSTRING:
pri_char_set = PRI_CHAR_SET_ISO10646_BMPSTRING;
break;
case AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING:
pri_char_set = PRI_CHAR_SET_ISO10646_UTF_8STRING;
break;
Richard Mudgett
committed
#if defined(HAVE_PRI_SUBADDR)
/*!
* \internal
* \brief Fill in the asterisk party subaddress from the given PRI party subaddress.
Kevin P. Fleming
committed
* \since 1.8
Richard Mudgett
committed
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
*
* \param ast_subaddress Asterisk party subaddress structure.
* \param pri_subaddress PRI party subaddress structure.
*
* \return Nothing
*
*/
static void sig_pri_set_subaddress(struct ast_party_subaddress *ast_subaddress, const struct pri_party_subaddress *pri_subaddress)
{
char *cnum, *ptr;
int x, len;
if (ast_subaddress->str) {
ast_free(ast_subaddress->str);
}
if (pri_subaddress->length <= 0) {
ast_party_subaddress_init(ast_subaddress);
return;
}
if (!pri_subaddress->type) {
/* NSAP */
ast_subaddress->str = ast_strdup((char *) pri_subaddress->data);
} else {
/* User Specified */
if (!(cnum = ast_malloc(2 * pri_subaddress->length + 1))) {
ast_party_subaddress_init(ast_subaddress);
return;
}
ptr = cnum;
len = pri_subaddress->length - 1; /* -1 account for zero based indexing */
for (x = 0; x < len; ++x) {
ptr += sprintf(ptr, "%02x", pri_subaddress->data[x]);
}
if (pri_subaddress->odd_even_indicator) {
/* ODD */
sprintf(ptr, "%01x", (pri_subaddress->data[len]) >> 4);
} else {
/* EVEN */
sprintf(ptr, "%02x", pri_subaddress->data[len]);
}
ast_subaddress->str = cnum;
}
ast_subaddress->type = pri_subaddress->type;
ast_subaddress->odd_even_indicator = pri_subaddress->odd_even_indicator;
ast_subaddress->valid = 1;
}
#endif /* defined(HAVE_PRI_SUBADDR) */
#if defined(HAVE_PRI_SUBADDR)
static unsigned char ast_pri_pack_hex_char(char c)
{
unsigned char res;
if (c < '0') {
res = 0;
} else if (c < ('9' + 1)) {
res = c - '0';
} else if (c < 'A') {
res = 0;
} else if (c < ('F' + 1)) {
res = c - 'A' + 10;
} else if (c < 'a') {
res = 0;
} else if (c < ('f' + 1)) {
res = c - 'a' + 10;
} else {
res = 0;
}
return res;
}
#endif /* defined(HAVE_PRI_SUBADDR) */
#if defined(HAVE_PRI_SUBADDR)
/*!
* \internal
* \brief Convert a null terminated hexadecimal string to a packed hex byte array.
* \details left justified, with 0 padding if odd length.
Kevin P. Fleming
committed
* \since 1.8
Richard Mudgett
committed
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
*
* \param dst pointer to packed byte array.
* \param src pointer to null terminated hexadecimal string.
* \param maxlen destination array size.
*
* \return Length of byte array
*
* \note The dst is not an ASCIIz string.
* \note The src is an ASCIIz hex string.
*/
static int ast_pri_pack_hex_string(unsigned char *dst, char *src, int maxlen)
{
int res = 0;
int len = strlen(src);
if (len > (2 * maxlen)) {
len = 2 * maxlen;
}
res = len / 2 + len % 2;
while (len > 1) {
*dst = ast_pri_pack_hex_char(*src) << 4;
src++;
*dst |= ast_pri_pack_hex_char(*src);
dst++, src++;
len -= 2;
}
if (len) { /* 1 left */
*dst = ast_pri_pack_hex_char(*src) << 4;
}
return res;
}
#endif /* defined(HAVE_PRI_SUBADDR) */
#if defined(HAVE_PRI_SUBADDR)
/*!
* \internal
* \brief Fill in the PRI party subaddress from the given asterisk party subaddress.
Kevin P. Fleming
committed
* \since 1.8
Richard Mudgett
committed
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
*
* \param pri_subaddress PRI party subaddress structure.
* \param ast_subaddress Asterisk party subaddress structure.
*
* \return Nothing
*
* \note Assumes that pri_subaddress has been previously memset to zero.
*/
static void sig_pri_party_subaddress_from_ast(struct pri_party_subaddress *pri_subaddress, const struct ast_party_subaddress *ast_subaddress)
{
if (ast_subaddress->valid && !ast_strlen_zero(ast_subaddress->str)) {
pri_subaddress->type = ast_subaddress->type;
if (!ast_subaddress->type) {
/* 0 = NSAP */
ast_copy_string((char *) pri_subaddress->data, ast_subaddress->str,
sizeof(pri_subaddress->data));
pri_subaddress->length = strlen((char *) pri_subaddress->data);
pri_subaddress->odd_even_indicator = 0;
pri_subaddress->valid = 1;
} else {
/* 2 = User Specified */
/*
* Copy HexString to packed HexData,
* if odd length then right pad trailing byte with 0
*/
int length = ast_pri_pack_hex_string(pri_subaddress->data,
ast_subaddress->str, sizeof(pri_subaddress->data));
pri_subaddress->length = length; /* packed data length */
length = strlen(ast_subaddress->str);
if (length > 2 * sizeof(pri_subaddress->data)) {
pri_subaddress->odd_even_indicator = 0;
} else {
pri_subaddress->odd_even_indicator = (length & 1);
}
Richard Mudgett
committed
pri_subaddress->valid = 1;
}
}
}
#endif /* defined(HAVE_PRI_SUBADDR) */
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
/*!
* \internal
* \brief Fill in the PRI party name from the given asterisk party name.
* \since 1.8
*
* \param pri_name PRI party name structure.
* \param ast_name Asterisk party name structure.
*
* \return Nothing
*
* \note Assumes that pri_name has been previously memset to zero.
*/
static void sig_pri_party_name_from_ast(struct pri_party_name *pri_name, const struct ast_party_name *ast_name)
{
if (!ast_name->valid) {
return;
}
pri_name->valid = 1;
pri_name->presentation = ast_to_pri_presentation(ast_name->presentation);
pri_name->char_set = ast_to_pri_char_set(ast_name->char_set);
if (!ast_strlen_zero(ast_name->str)) {
ast_copy_string(pri_name->str, ast_name->str, sizeof(pri_name->str));
}
}
/*!
* \internal
* \brief Fill in the PRI party number from the given asterisk party number.
* \since 1.8
*
* \param pri_number PRI party number structure.
* \param ast_number Asterisk party number structure.
*
* \return Nothing
*
* \note Assumes that pri_number has been previously memset to zero.
*/
static void sig_pri_party_number_from_ast(struct pri_party_number *pri_number, const struct ast_party_number *ast_number)
{
if (!ast_number->valid) {
return;
}
pri_number->valid = 1;
pri_number->presentation = ast_to_pri_presentation(ast_number->presentation);
pri_number->plan = ast_number->plan;
if (!ast_strlen_zero(ast_number->str)) {
ast_copy_string(pri_number->str, ast_number->str, sizeof(pri_number->str));
}
}
/*!
* \internal
* \brief Fill in the PRI party id from the given asterisk party id.
Kevin P. Fleming
committed
* \since 1.8
*
* \param pri_id PRI party id structure.
* \param ast_id Asterisk party id structure.
*
* \return Nothing
*
* \note Assumes that pri_id has been previously memset to zero.
*/
static void sig_pri_party_id_from_ast(struct pri_party_id *pri_id, const struct ast_party_id *ast_id)
{
sig_pri_party_name_from_ast(&pri_id->name, &ast_id->name);
sig_pri_party_number_from_ast(&pri_id->number, &ast_id->number);
Richard Mudgett
committed
#if defined(HAVE_PRI_SUBADDR)
sig_pri_party_subaddress_from_ast(&pri_id->subaddress, &ast_id->subaddress);
#endif /* defined(HAVE_PRI_SUBADDR) */
}
/*!
* \internal
* \brief Update the PRI redirecting information for the current call.
Kevin P. Fleming
committed
* \since 1.8
*
* \param pvt sig_pri private channel structure.
* \param ast Asterisk channel
*
* \return Nothing
*
* \note Assumes that the PRI lock is already obtained.
*/
static void sig_pri_redirecting_update(struct sig_pri_chan *pvt, struct ast_channel *ast)
{
struct pri_party_redirecting pri_redirecting;
const struct ast_party_redirecting *ast_redirecting;
Richard Mudgett
committed
struct ast_party_id redirecting_from = ast_channel_redirecting_effective_from(ast);
struct ast_party_id redirecting_to = ast_channel_redirecting_effective_to(ast);
struct ast_party_id redirecting_orig = ast_channel_redirecting_effective_orig(ast);
memset(&pri_redirecting, 0, sizeof(pri_redirecting));
ast_redirecting = ast_channel_redirecting(ast);
Richard Mudgett
committed
sig_pri_party_id_from_ast(&pri_redirecting.from, &redirecting_from);
sig_pri_party_id_from_ast(&pri_redirecting.to, &redirecting_to);
sig_pri_party_id_from_ast(&pri_redirecting.orig_called, &redirecting_orig);
pri_redirecting.count = ast_redirecting->count;
pri_redirecting.orig_reason = ast_to_pri_reason(ast_redirecting->orig_reason);
pri_redirecting.reason = ast_to_pri_reason(ast_redirecting->reason);
pri_redirecting_update(pvt->pri->pri, pvt->call, &pri_redirecting);
}
/*!
* \internal
* \brief Reset DTMF detector.
Kevin P. Fleming
committed
* \since 1.8
*
* \param p sig_pri channel structure.
*
* \return Nothing
*/
static void sig_pri_dsp_reset_and_flush_digits(struct sig_pri_chan *p)
{
if (sig_pri_callbacks.dsp_reset_and_flush_digits) {
sig_pri_callbacks.dsp_reset_and_flush_digits(p->chan_pvt);
}
}
static int sig_pri_set_echocanceller(struct sig_pri_chan *p, int enable)
{
if (sig_pri_callbacks.set_echocanceller) {
return sig_pri_callbacks.set_echocanceller(p->chan_pvt, enable);
} else {
return -1;
static void sig_pri_fixup_chans(struct sig_pri_chan *old_chan, struct sig_pri_chan *new_chan)
if (sig_pri_callbacks.fixup_chans) {
sig_pri_callbacks.fixup_chans(old_chan->chan_pvt, new_chan->chan_pvt);
}
}
static int sig_pri_play_tone(struct sig_pri_chan *p, enum sig_pri_tone tone)
{
if (sig_pri_callbacks.play_tone) {
return sig_pri_callbacks.play_tone(p->chan_pvt, tone);
} else {
return -1;
static struct ast_channel *sig_pri_new_ast_channel(struct sig_pri_chan *p, int state, int ulaw, int transfercapability, char *exten, const struct ast_channel *requestor)
{
struct ast_channel *c;
if (sig_pri_callbacks.new_ast_channel) {
c = sig_pri_callbacks.new_ast_channel(p->chan_pvt, state, ulaw, exten, requestor);
return NULL;
}
if (!c) {
return NULL;
}
if (!p->owner)
p->owner = c;
p->isidlecall = 0;
p->alreadyhungup = 0;
ast_channel_transfercapability_set(c, transfercapability);
pbx_builtin_setvar_helper(c, "TRANSFERCAPABILITY",
ast_transfercapability2str(transfercapability));
if (transfercapability & AST_TRANS_CAP_DIGITAL) {
sig_pri_set_digital(p, 1);
}
if (p->pri) {
ast_mutex_lock(&p->pri->lock);
sig_pri_span_devstate_changed(p->pri);
ast_mutex_unlock(&p->pri->lock);
return c;
}
/*!
* \internal
* \brief Open the PRI channel media path.