Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: build_tools/menuselect-deps.in
- ===================================================================
- --- build_tools/menuselect-deps.in 2010-12-17 19:40:56.000000000 -0200
- +++ build_tools/menuselect-deps.in 2011-06-30 14:38:51.000000000 -0300
- @@ -26,6 +26,7 @@
- PGSQL=@PBX_PGSQL@
- POPT=@PBX_POPT@
- PRI=@PBX_PRI@
- +OPENR2=@PBX_OPENR2@
- RADIUS=@PBX_RADIUS@
- SPEEX=@PBX_SPEEX@
- SPEEXDSP=@PBX_SPEEXDSP@
- ===================================================================
- Index: channels/chan_dahdi.c
- ===================================================================
- --- asterisk-1.4.42/channels/chan_dahdi.c 2011-04-11 12:27:52.000000000 -0300
- +++ asterisk-1.4.42-alt/channels/chan_dahdi.c 2011-06-30 16:32:10.000000000 -0300
- @@ -43,6 +43,7 @@
- <depend>tonezone</depend>
- <depend>res_features</depend>
- <use>pri</use>
- + <use>openr2</use>
- ***/
- #include "asterisk.h"
- @@ -71,6 +72,10 @@
- #include <libpri.h>
- #endif
- +#ifdef HAVE_OPENR2
- +#include <openr2.h>
- +#endif
- +
- #include "asterisk/lock.h"
- #include "asterisk/channel.h"
- #include "asterisk/config.h"
- @@ -170,6 +175,10 @@
- #ifdef HAVE_PRI
- " w/PRI"
- #endif
- +
- +#ifdef HAVE_OPENR2
- + " w/OPENR2"
- +#endif
- ;
- #define SIG_EM DAHDI_SIG_EM
- @@ -188,6 +197,7 @@
- #define SIG_FXOGS DAHDI_SIG_FXOGS
- #define SIG_FXOKS DAHDI_SIG_FXOKS
- #define SIG_PRI DAHDI_SIG_CLEAR
- +#define SIG_MFCR2 DAHDI_SIG_CAS
- #define SIG_SF DAHDI_SIG_SF
- #define SIG_SFWINK (0x0100000 | DAHDI_SIG_SF)
- #define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
- @@ -316,6 +326,45 @@
- */
- static int ringt_base = DEFAULT_RINGT;
- +#ifdef HAVE_OPENR2
- +
- +struct dahdi_mfcr2 {
- + pthread_t master; /*!< Thread of master */
- + openr2_context_t *protocol_context; /*!< OpenR2 context handle */
- + struct dahdi_pvt *pvts[MAX_CHANNELS]; /*!< Member channel pvt structs */
- + int numchans; /*!< Number of channels in this R2 block */
- +};
- +
- +static struct dahdi_mfcr2 r2links[NUM_SPANS];
- +static openr2_variant_t mfcr2_cur_variant = OR2_VAR_UNKNOWN;
- +static int mfcr2_cur_mfback_timeout = -1;
- +static int mfcr2_cur_metering_pulse_timeout = -1;
- +static int mfcr2_cur_max_ani = 10;
- +static int mfcr2_cur_max_dnis = 4;
- +static int mfcr2_cur_get_ani_first = -1;
- +static int mfcr2_cur_skip_category = -1;
- +static int mfcr2_cur_context_index = 0;
- +static int mfcr2_cur_call_files = 0;
- +static int mfcr2_cur_allow_collect_calls = 0;
- +static int mfcr2_cur_accept_on_offer = 1;
- +static int mfcr2_cur_charge_calls = 1;
- +static int mfcr2_cur_forced_release = 0;
- +static int mfcr2_cur_double_answer = 0;
- +static int mfcr2_cur_immediate_accept = -1;
- +/* starting with openr2 interface 3 we have DTMF support */
- +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
- +static int mfcr2_cur_dtmf_dialing = -1;
- +static int mfcr2_cur_dtmf_detection = -1;
- +static int mfcr2_cur_dtmf_time_on = OR2_DEFAULT_DTMF_ON;
- +static int mfcr2_cur_dtmf_time_off = OR2_DEFAULT_DTMF_OFF;
- +#endif
- +static char mfcr2_cur_logdir[OR2_MAX_PATH];
- +static char mfcr2_cur_r2proto_file[OR2_MAX_PATH];
- +static openr2_log_level_t mfcr2_cur_loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING;
- +static openr2_calling_party_category_t mfcr2_cur_category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
- +
- +#endif /* HAVE_OPENR2 */
- +
- #ifdef HAVE_PRI
- #define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8) | (p->pri->mastertrunkgroup ? 0x10000 : 0))
- @@ -927,6 +976,24 @@
- /*! \brief Logical span number within trunk group */
- int logicalspan;
- #endif
- +
- +#ifdef HAVE_OPENR2
- + int mfcr2call;
- + int mfcr2block;
- + struct dahdi_mfcr2 *mfcr2;
- + openr2_chan_t *r2chan;
- + openr2_calling_party_category_t mfcr2_recvd_category;
- + openr2_calling_party_category_t mfcr2_category;
- + int mfcr2_accept_on_offer;
- + int mfcr2_charge_calls;
- + int mfcr2_allow_collect_calls;
- + int mfcr2_forced_release;
- + int mfcr2_dnis_index;
- + int mfcr2_ani_index;
- + int mfcr2_dnis_matched;
- + int mfcr2_call_accepted;
- +#endif
- +
- /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
- int polarity;
- /*! \brief DSP feature flags: DSP_FEATURE_xxx */
- @@ -1248,6 +1315,512 @@
- #endif
- }
- +static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int index, int law, int transfercapability);
- +#ifdef HAVE_OPENR2
- +static void init_mfcr2_globals(void)
- +{
- + int r;
- + mfcr2_cur_context_index = 0;
- + mfcr2_cur_variant = OR2_VAR_UNKNOWN;
- + mfcr2_cur_mfback_timeout = -1;
- + mfcr2_cur_metering_pulse_timeout = -1;
- + mfcr2_cur_max_ani = 10;
- + mfcr2_cur_max_dnis = 4;
- + mfcr2_cur_get_ani_first = -1;
- +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
- + mfcr2_cur_dtmf_dialing = -1;
- + mfcr2_cur_dtmf_detection = -1;
- + mfcr2_cur_dtmf_time_on = OR2_DEFAULT_DTMF_ON;
- + mfcr2_cur_dtmf_time_off = OR2_DEFAULT_DTMF_OFF;
- +#endif
- + mfcr2_cur_skip_category = -1;
- + mfcr2_cur_call_files = 0;
- + mfcr2_cur_allow_collect_calls = 0;
- + mfcr2_cur_forced_release = 0;
- + mfcr2_cur_double_answer = 0;
- + mfcr2_cur_immediate_accept = -1;
- + mfcr2_cur_loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING;
- + mfcr2_cur_category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
- + memset(mfcr2_cur_logdir, 0, sizeof(mfcr2_cur_logdir));
- + memset(mfcr2_cur_r2proto_file, 0, sizeof(mfcr2_cur_r2proto_file));
- + memset(r2links, 0, sizeof(r2links));
- + for (r = 0; r < NUM_SPANS; r++) {
- + r2links[r].master = AST_PTHREADT_NULL;
- + }
- +}
- +
- +static int dahdi_r2_answer(struct dahdi_pvt *p)
- +{
- + int res = 0;
- + /* openr2 1.1.0 and older does not even define OR2_LIB_INTERFACE
- + * and does not has support for openr2_chan_answer_call_with_mode
- + * */
- +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
- + const char *double_answer = pbx_builtin_getvar_helper(p->owner, "MFCR2_DOUBLE_ANSWER");
- + int wants_double_answer = ast_true(double_answer) ? 1 : 0;
- + if (!double_answer) {
- + /* this still can result in double answer if the channel context
- + * was configured that way */
- + res = openr2_chan_answer_call(p->r2chan);
- + } else if (wants_double_answer) {
- + res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_DOUBLE);
- + } else {
- + res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_SIMPLE);
- + }
- +#else
- + res = openr2_chan_answer_call(p->r2chan);
- +#endif
- + return res;
- +}
- +
- +static openr2_calling_party_category_t dahdi_r2_get_channel_category(struct ast_channel *c)
- +{
- + openr2_calling_party_category_t cat;
- + const char *catstr = pbx_builtin_getvar_helper(c, "MFCR2_CATEGORY");
- + struct dahdi_pvt *p = c->tech_pvt;
- + if (ast_strlen_zero(catstr)) {
- + ast_log(LOG_DEBUG, "no MFC/R2 category specified for chan %s, using default %s\n",
- + c->name, openr2_proto_get_category_string(p->mfcr2_category));
- + return p->mfcr2_category;
- + }
- + if ((cat = openr2_proto_get_category(catstr)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
- + ast_log(LOG_WARNING, "Invalid category specified '%s' for chan %s, using default %s\n",
- + catstr, c->name, openr2_proto_get_category_string(p->mfcr2_category));
- + return p->mfcr2_category;
- + }
- + ast_log(LOG_DEBUG, "Using category %s\n", catstr);
- + return cat;
- +}
- +
- +static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + ast_mutex_lock(&p->lock);
- + if (p->mfcr2call) {
- + ast_mutex_unlock(&p->lock);
- + /* TODO: This can happen when some other thread just finished zt_request requesting this very same
- + interface but has not yet seized the line (zt_call), and the far end wins and seize the line,
- + can we avoid this somehow?, at this point when zt_call send the seize, it is likely that since
- + the other end will see our seize as a forced release and drop the call, we will see an invalid
- + pattern that will be seen and treated as protocol error. */
- + ast_log(LOG_ERROR, "Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan));
- + return;
- + }
- + p->mfcr2call = 1;
- + /* better safe than sorry ... */
- + p->cid_name[0] = 0;
- + p->cid_num[0] = 0;
- + p->rdnis[0] = 0;
- + p->exten[0] = 0;
- + p->mfcr2_ani_index = 0;
- + p->mfcr2_dnis_index = 0;
- + p->mfcr2_dnis_matched = 0;
- + p->mfcr2_call_accepted = 0;
- + ast_mutex_unlock(&p->lock);
- + ast_verbose("New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
- +}
- +
- +static void handle_alarms(struct dahdi_pvt *p, int alarms);
- +static int get_alarms(struct dahdi_pvt *p);
- +static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
- +{
- + int res;
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + ast_mutex_lock(&p->lock);
- + p->inalarm = alarm ? 1 : 0;
- + if (p->inalarm) {
- + res = get_alarms(p);
- + /* unknown_alarm may be set here */
- + handle_alarms(p, res);
- + } else {
- + if (!p->unknown_alarm) {
- + ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
- + manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
- + } else {
- + p->unknown_alarm = 0;
- + }
- + }
- + ast_mutex_unlock(&p->lock);
- + ast_log(LOG_WARNING, "Zap alarm on chan %d.\n", openr2_chan_get_number(r2chan));
- +}
- +
- +static void dahdi_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
- +{
- + ast_log(LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
- +}
- +
- +static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + ast_log(LOG_ERROR, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
- + if (p->owner) {
- + p->owner->hangupcause = AST_CAUSE_PROTOCOL_ERROR;
- + p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- + }
- + ast_mutex_lock(&p->lock);
- + p->mfcr2call = 0;
- + ast_mutex_unlock(&p->lock);
- +}
- +
- +static void dahdi_r2_disconnect_call(struct dahdi_pvt *p, openr2_call_disconnect_cause_t cause)
- +{
- + if (openr2_chan_disconnect_call(p->r2chan, cause)) {
- + ast_log(LOG_NOTICE, "Bad! failed to disconnect call on channel %d with reason %s, hope for the best!\n",
- + p->channel, openr2_proto_get_disconnect_string(cause));
- + /* force the chan to idle and release the call flag now since we will not see a clean on_call_end */
- + openr2_chan_set_idle(p->r2chan);
- + ast_mutex_lock(&p->lock);
- + p->mfcr2call = 0;
- + ast_mutex_unlock(&p->lock);
- + }
- +}
- +
- +static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
- +{
- + struct dahdi_pvt *p;
- + struct ast_channel *c;
- + ast_verbose("MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
- + openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis, openr2_proto_get_category_string(category));
- + p = openr2_chan_get_client_data(r2chan);
- + if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
- + ast_log(LOG_NOTICE, "Rejecting MFC/R2 collect call on chan %d\n", p->channel);
- + dahdi_r2_disconnect_call(p, OR2_CAUSE_COLLECT_CALL_REJECTED);
- + return;
- + }
- + ast_mutex_lock(&p->lock);
- + p->mfcr2_recvd_category = category;
- + /* if we're not supposed to use CID, clear whatever we have */
- + if (!p->use_callerid) {
- + ast_log(LOG_DEBUG, "No CID allowed in configuration, CID is being cleared!\n");
- + p->cid_num[0] = 0;
- + p->cid_name[0] = 0;
- + }
- + /* if we're supposed to answer immediately, clear DNIS and set 's' exten */
- + if (p->immediate || !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan))) {
- + ast_log(LOG_DEBUG, "Setting exten => s because of immediate or 0 DNIS configured\n");
- + p->exten[0] = 's';
- + p->exten[1] = 0;
- + }
- + ast_mutex_unlock(&p->lock);
- + if (!ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
- + ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
- + p->channel, p->exten, p->context);
- + dahdi_r2_disconnect_call(p, OR2_CAUSE_UNALLOCATED_NUMBER);
- + } else {
- + /* if the user does not want to accept on offer, then we should launch the PBX thread now */
- + if (!p->mfcr2_accept_on_offer) {
- + c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, 0);
- + if (!c) {
- + ast_log(LOG_ERROR, "Unable to create PBX channel on chan %d\n", p->channel);
- + dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
- + }
- + /* Don't disable reading since we still need to generate MF tone to accept
- + the call or reject it and detect the tone off condition of the other end */
- + } else if (p->mfcr2_charge_calls) {
- + ast_log(LOG_DEBUG, "Accepting MFC/R2 call on offer with charge on chan %d\n", p->channel);
- + openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
- + } else {
- + ast_log(LOG_DEBUG, "Accepting MFC/R2 call on offer with no charge on chan %d\n", p->channel);
- + openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
- + }
- + }
- +}
- +
- +static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + ast_verbose("MFC/R2 call end on chan %d\n", p->channel);
- + ast_mutex_lock(&p->lock);
- + p->mfcr2call = 0;
- + ast_mutex_unlock(&p->lock);
- +}
- +
- +static void dahdi_enable_ec(struct dahdi_pvt *p);
- +static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
- +{
- + struct dahdi_pvt *p = NULL;
- + struct ast_channel *c = NULL;
- + p = openr2_chan_get_client_data(r2chan);
- + dahdi_enable_ec(p);
- + p->mfcr2_call_accepted = 1;
- + if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
- + ast_verbose("MFC/R2 call has been accepted on backward channel %d\n", openr2_chan_get_number(r2chan));
- + /* if accept on offer is not set, it means at this point the PBX thread is already
- + launched and therefore this callback is being executed in the PBX thread rather than
- + the monitor thread, don't launch any other thread, just disable the R2 reading and
- + answer the call */
- + if (!p->mfcr2_accept_on_offer) {
- + openr2_chan_disable_read(r2chan);
- + ast_verbose("Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
- + dahdi_r2_answer(p);
- + return;
- + }
- + c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, 0);
- + if (c) {
- + /* chan_dahdi will take care of reading from now on, tell the library to forget about it */
- + openr2_chan_disable_read(r2chan);
- + } else {
- + ast_log(LOG_ERROR, "Unable to create PBX channel on chan %d\n", p->channel);
- + dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
- + return;
- + }
- + } else {
- + ast_verbose("Call accepted on forward channel %d\n", p->channel);
- + p->subs[SUB_REAL].needringing = 1;
- + p->dialing = 0;
- + /* chan_dahdi will take care of reading from now on, tell the library to forget about it */
- + openr2_chan_disable_read(r2chan);
- + }
- +}
- +
- +static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + ast_verbose("MFC/R2 call has been answered on chan %d\n", openr2_chan_get_number(r2chan));
- + p->subs[SUB_REAL].needanswer = 1;
- +}
- +
- +static void dahdi_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
- +{
- + /*ast_log(LOG_DEBUG, "Read data from dahdi channel %d\n", openr2_chan_get_number(r2chan));*/
- +}
- +
- +/*static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
- +{
- + switch (cause) {
- + case OR2_CAUSE_BUSY_NUMBER:
- + return AST_CAUSE_BUSY;
- + case OR2_CAUSE_NETWORK_CONGESTION:
- + return AST_CAUSE_CONGESTION;
- + case OR2_CAUSE_OUT_OF_ORDER:
- + return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
- + case OR2_CAUSE_UNALLOCATED_NUMBER:
- + return AST_CAUSE_UNREGISTERED;
- + case OR2_CAUSE_NO_ANSWER:
- + return AST_CAUSE_NO_ANSWER;
- + case OR2_CAUSE_NORMAL_CLEARING:
- + return AST_CAUSE_NORMAL_CLEARING;
- + case OR2_CAUSE_UNSPECIFIED:
- + default:
- + return AST_CAUSE_NOTDEFINED;
- + }
- +}*/
- +
- +static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + ast_verbose("MFC/R2 call disconnected on chan %d\n", openr2_chan_get_number(r2chan));
- + ast_mutex_lock(&p->lock);
- + if (p->owner) {
- + /* when we have an owner we don't call openr2_chan_disconnect_call here, that will
- + be done in zt_hangup */
- + if (p->owner->_state == AST_STATE_UP) {
- + p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- + ast_mutex_unlock(&p->lock);
- + } else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
- + /* being the forward side we must report what happened to the call to whoever requested it */
- + switch (cause) {
- + case OR2_CAUSE_BUSY_NUMBER:
- + p->owner->hangupcause = AST_CAUSE_BUSY;
- + p->subs[SUB_REAL].needbusy = 1;
- + break;
- + case OR2_CAUSE_NUMBER_CHANGED:
- + p->owner->hangupcause = AST_CAUSE_NUMBER_CHANGED;
- + p->subs[SUB_REAL].needcongestion = 1;
- + break;
- + case OR2_CAUSE_NETWORK_CONGESTION:
- + p->owner->hangupcause = AST_CAUSE_NETWORK_OUT_OF_ORDER;
- + p->subs[SUB_REAL].needcongestion = 1;
- + break;
- + case OR2_CAUSE_OUT_OF_ORDER:
- + p->owner->hangupcause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
- + p->subs[SUB_REAL].needcongestion = 1;
- + break;
- + case OR2_CAUSE_UNALLOCATED_NUMBER:
- + p->owner->hangupcause = AST_CAUSE_UNALLOCATED;
- + p->subs[SUB_REAL].needcongestion = 1;
- + break;
- + case OR2_CAUSE_NO_ANSWER:
- + p->owner->hangupcause = AST_CAUSE_NO_ANSWER;
- + p->subs[SUB_REAL].needcongestion = 1;
- + break;
- + case OR2_CAUSE_UNSPECIFIED:
- + p->owner->hangupcause = AST_CAUSE_NOTDEFINED;
- + p->subs[SUB_REAL].needcongestion = 1;
- + break;
- + case OR2_CAUSE_NORMAL_CLEARING:
- + p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
- + p->subs[SUB_REAL].needcongestion = 1;
- + break;
- + default:
- + ast_log(LOG_WARNING, "Unhandled cause %d\n", cause);
- + }
- + p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- + ast_mutex_unlock(&p->lock);
- + } else {
- + ast_mutex_unlock(&p->lock);
- + /* being the backward side and not UP yet, we only need to request hangup */
- + /* TODO: what about doing this same thing when were AST_STATE_UP? */
- + ast_queue_hangup(p->owner);
- + }
- + } else {
- + ast_mutex_unlock(&p->lock);
- + /* no owner, therefore we can't use zt_hangup to disconnect, do it right now */
- + dahdi_r2_disconnect_call(p, OR2_CAUSE_NORMAL_CLEARING);
- + }
- +}
- +
- +static void dahdi_r2_write_log(openr2_log_level_t level, char *logmessage)
- +{
- + switch (level) {
- + case OR2_LOG_NOTICE:
- + ast_verbose("%s", logmessage);
- + break;
- + case OR2_LOG_WARNING:
- + ast_log(LOG_WARNING, "%s", logmessage);
- + break;
- + case OR2_LOG_ERROR:
- + ast_log(LOG_ERROR, "%s", logmessage);
- + break;
- + case OR2_LOG_STACK_TRACE:
- + case OR2_LOG_MF_TRACE:
- + case OR2_LOG_CAS_TRACE:
- + case OR2_LOG_DEBUG:
- + case OR2_LOG_EX_DEBUG:
- + ast_log(LOG_DEBUG, "%s", logmessage);
- + break;
- + default:
- + ast_log(LOG_WARNING, "We should handle logging level %d here.\n", level);
- + ast_log(LOG_NOTICE, "%s", logmessage);
- + break;
- + }
- +}
- +
- +#define DAHDI_R2_REMOTE_BLOCK (1 << 0)
- +#define DAHDI_R2_LOCAL_BLOCK (1 << 1)
- +static void dahdi_r2_on_line_blocked(openr2_chan_t *r2chan)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + ast_log(LOG_NOTICE, "Far end blocked on chan %d\n", p->channel);
- + ast_mutex_lock(&p->lock);
- + p->mfcr2block |= DAHDI_R2_REMOTE_BLOCK;
- + ast_mutex_unlock(&p->lock);
- +}
- +
- +static void dahdi_r2_on_line_idle(openr2_chan_t *r2chan)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + ast_log(LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
- + ast_mutex_lock(&p->lock);
- + p->mfcr2block &= ~DAHDI_R2_REMOTE_BLOCK;
- + ast_mutex_unlock(&p->lock);
- +}
- +
- +static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
- + __attribute__((format (printf, 3, 0)));
- +static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
- +{
- + char logmsg[256];
- + char completemsg[sizeof(logmsg)+50];
- + vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
- + snprintf(completemsg, sizeof(completemsg), "Context - %s", logmsg);
- + dahdi_r2_write_log(level, completemsg);
- +}
- +
- +static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
- + __attribute__((format (printf, 3, 0)));
- +static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
- +{
- + char logmsg[256];
- + char completemsg[sizeof(logmsg)+50];
- + vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
- + snprintf(completemsg, sizeof(completemsg), "Chan %d - %s", openr2_chan_get_number(r2chan), logmsg);
- + dahdi_r2_write_log(level, completemsg);
- +}
- +
- +static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + /* if 'immediate' is set, let's stop requesting DNIS */
- + if (p->immediate) {
- + return 0;
- + }
- + p->exten[p->mfcr2_dnis_index] = digit;
- + p->rdnis[p->mfcr2_dnis_index] = digit;
- + p->mfcr2_dnis_index++;
- + p->exten[p->mfcr2_dnis_index] = 0;
- + p->rdnis[p->mfcr2_dnis_index] = 0;
- + /*
- + ast_log(LOG_DEBUG, "Got digit %c in dahdi, dnis so far: %s\n", digit, p->exten);
- + int ret;
- + ret = ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num);
- + ast_log(LOG_DEBUG, "ast_exists_extension(%s, %s, 1, %s) = %d\n", p->context, p->exten, p->cid_num, ret);
- + ret = ast_matchmore_extension(NULL, p->context, p->exten, 1, p->cid_num);
- + ast_log(LOG_DEBUG, "ast_matchmore_extension(%s, %s, 1, %s) = %d\n", p->context, p->exten, p->cid_num, ret);
- + */
- + /* if the DNIS is a match and cannot match more, stop requesting DNIS */
- + if ((p->mfcr2_dnis_matched ||
- + (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num) && (p->mfcr2_dnis_matched = 1))) &&
- + !ast_matchmore_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
- + return 0;
- + }
- + /* otherwise keep going */
- + return 1;
- +}
- +
- +static void dahdi_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
- +{
- + struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
- + p->cid_num[p->mfcr2_ani_index] = digit;
- + p->cid_name[p->mfcr2_ani_index] = digit;
- + p->mfcr2_ani_index++;
- + p->cid_num[p->mfcr2_ani_index] = 0;
- + p->cid_name[p->mfcr2_ani_index] = 0;
- +}
- +
- +static void dahdi_r2_on_billing_pulse_received(openr2_chan_t *r2chan)
- +{
- + ast_log(LOG_NOTICE, "MFC/R2 billing pulse received on channel %d\n", openr2_chan_get_number(r2chan));
- +}
- +
- +static openr2_event_interface_t dahdi_r2_event_iface = {
- + .on_call_init = dahdi_r2_on_call_init,
- + .on_call_offered = dahdi_r2_on_call_offered,
- + .on_call_accepted = dahdi_r2_on_call_accepted,
- + .on_call_answered = dahdi_r2_on_call_answered,
- + .on_call_disconnect = dahdi_r2_on_call_disconnect,
- + .on_call_end = dahdi_r2_on_call_end,
- + .on_call_read = dahdi_r2_on_call_read,
- + .on_hardware_alarm = dahdi_r2_on_hardware_alarm,
- + .on_os_error = dahdi_r2_on_os_error,
- + .on_protocol_error = dahdi_r2_on_protocol_error,
- + .on_line_blocked = dahdi_r2_on_line_blocked,
- + .on_line_idle = dahdi_r2_on_line_idle,
- + /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
- + .on_context_log = (openr2_handle_context_logging_func)dahdi_r2_on_context_log,
- + .on_dnis_digit_received = dahdi_r2_on_dnis_digit_received,
- + .on_ani_digit_received = dahdi_r2_on_ani_digit_received,
- + /* so far we do nothing with billing pulses, just log it */
- + .on_billing_pulse_received = dahdi_r2_on_billing_pulse_received
- +};
- +
- +static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample)
- +{
- + return AST_ALAW(sample);
- +}
- +
- +static inline uint8_t dahdi_r2_linear_to_alaw(int sample)
- +{
- + return AST_LIN2A(sample);
- +}
- +
- +static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
- + dahdi_r2_alaw_to_linear,
- + dahdi_r2_linear_to_alaw
- +};
- +
- +#endif /* HAVE_OPENR2 */
- +
- static int restore_gains(struct dahdi_pvt *p);
- static void swap_subs(struct dahdi_pvt *p, int a, int b)
- @@ -1637,6 +2210,8 @@
- return "FXO Kewlstart";
- case SIG_PRI:
- return "ISDN PRI";
- + case SIG_MFCR2:
- + return "MFC/R2";
- case SIG_SF:
- return "SF (Tone) Immediate";
- case SIG_SFWINK:
- @@ -2486,6 +3061,7 @@
- ast_setstate(ast, AST_STATE_UP);
- break;
- case SIG_PRI:
- + case SIG_MFCR2:
- /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
- p->dialdest[0] = '\0';
- p->dialing = 1;
- @@ -2495,6 +3071,37 @@
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- +
- +#ifdef HAVE_OPENR2
- + if (p->mfcr2) {
- + int strip = p->stripmsd;
- + int callres = 0;
- + c = strchr(dest, '/');
- + if (c) {
- + c++;
- + } else {
- + c = dest;
- + }
- + if (!p->hidecallerid) {
- + l = ast->cid.cid_num;
- + } else {
- + l = NULL;
- + }
- + if (strlen(c) < strip) {
- + ast_log(LOG_WARNING, "Destiny number '%s' is shorter than stripmsd(%d)? hum, you should fix that. Assuming stripmsd = 0\n", c, strip);
- + strip = 0;
- + }
- + p->dialing = 1;
- + callres = openr2_chan_make_call(p->r2chan, l, (c + strip), dahdi_r2_get_channel_category(ast));
- + if (-1 == callres) {
- + ast_mutex_unlock(&p->lock);
- + ast_log(LOG_ERROR, "unable to make new MFC/R2 call!\n");
- + return -1;
- + }
- + ast_setstate(ast, AST_STATE_DIALING);
- + }
- +#endif /* HAVE_OPENR2 */
- +
- #ifdef HAVE_PRI
- if (p->pri) {
- struct pri_sr *sr;
- @@ -2907,6 +3514,166 @@
- return 0;
- }
- #endif
- +
- +#ifdef HAVE_OPENR2
- +static char *dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
- +static char *zap_accept_r2_call_app = "ZapAcceptR2Call";
- +
- +static char *dahdi_accept_r2_call_synopsis = "Accept an R2 call if its not already accepted (you still need to answer it)";
- +static char *zap_accept_r2_call_synopsis = "Accept an R2 call if its not already accepted (you still need to answer it)";
- +
- +static char *dahdi_accept_r2_call_descrip =
- +" DAHDIAcceptR2Call(): This application will accept the current MFC/R2 call\n"
- +" You can specify yes or no as argument to accept with or without charge.\n";
- +
- +static char *zap_accept_r2_call_descrip =
- +" ZapAcceptR2Call(): This application will accept the current MFC/R2 call\n"
- +" You can specify yes or no as argument to accept with or without charge.\n";
- +
- +static int dahdi_accept_r2_call_exec(struct ast_channel *chan, void *data)
- +{
- + /* data is whether to accept with charge or no charge */
- + openr2_call_mode_t accept_mode;
- + int res, timeout, maxloops;
- + struct ast_frame *f;
- + struct dahdi_pvt *p;
- + char *parse;
- + AST_DECLARE_APP_ARGS(args,
- + AST_APP_ARG(charge);
- + );
- +
- + if (ast_strlen_zero(data)) {
- + ast_log(LOG_DEBUG, "No data sent to application!\n");
- + return -1;
- + }
- +
- + if (chan->tech != &dahdi_tech) {
- + ast_log(LOG_DEBUG, "Only DAHDI technology accepted!\n");
- + return -1;
- + }
- +
- + p = (struct dahdi_pvt *)chan->tech_pvt;
- + if (!p) {
- + ast_log(LOG_DEBUG, "Unable to find technology private!\n");
- + return -1;
- + }
- +
- + parse = ast_strdupa(data);
- + AST_STANDARD_APP_ARGS(args, parse);
- +
- + if (ast_strlen_zero(args.charge)) {
- + ast_log(LOG_WARNING, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
- + return -1;
- + }
- +
- + ast_mutex_lock(&p->lock);
- + if (!p->mfcr2 || !p->mfcr2call) {
- + ast_mutex_unlock(&p->lock);
- + ast_log(LOG_DEBUG, "Channel %s does not seems to be an R2 active channel!\n", chan->name);
- + return -1;
- + }
- +
- + if (p->mfcr2_call_accepted) {
- + ast_mutex_unlock(&p->lock);
- + ast_log(LOG_DEBUG, "MFC/R2 call already accepted on channel %s!\n", chan->name);
- + return 0;
- + }
- + accept_mode = ast_true(args.charge) ? OR2_CALL_WITH_CHARGE : OR2_CALL_NO_CHARGE;
- + if (openr2_chan_accept_call(p->r2chan, accept_mode)) {
- + ast_mutex_unlock(&p->lock);
- + ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
- + return -1;
- + }
- + ast_mutex_unlock(&p->lock);
- +
- + res = 0;
- + timeout = 100;
- + maxloops = 50; /* wait up to 5 seconds */
- + /* we need to read() until the call is accepted */
- + while (maxloops > 0) {
- + maxloops--;
- + if (ast_check_hangup(chan)) {
- + break;
- + }
- + res = ast_waitfor(chan, timeout);
- + if (res < 0) {
- + ast_log(LOG_DEBUG, "ast_waitfor failed on channel %s, going out ...\n", chan->name);
- + res = -1;
- + break;
- + }
- + if (res == 0) {
- + continue;
- + }
- + f = ast_read(chan);
- + if (!f) {
- + ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
- + res = -1;
- + break;
- + }
- + if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
- + ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
- + ast_frfree(f);
- + res = -1;
- + break;
- + }
- + ast_frfree(f);
- + ast_mutex_lock(&p->lock);
- + if (p->mfcr2_call_accepted) {
- + ast_mutex_unlock(&p->lock);
- + ast_log(LOG_DEBUG, "Accepted MFC/R2 call!\n");
- + break;
- + }
- + ast_mutex_unlock(&p->lock);
- + }
- + if (res == -1) {
- + ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
- + }
- + return res;
- +}
- +
- +static int zap_accept_r2_call_exec(struct ast_channel *chan, void *data)
- +{
- + return dahdi_accept_r2_call_exec(chan, data);
- +}
- +
- +static openr2_call_disconnect_cause_t dahdi_ast_cause_to_r2_cause(int cause)
- +{
- + openr2_call_disconnect_cause_t r2cause = OR2_CAUSE_NORMAL_CLEARING;
- + switch (cause) {
- + case AST_CAUSE_USER_BUSY:
- + case AST_CAUSE_CALL_REJECTED:
- + case AST_CAUSE_INTERWORKING: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
- + r2cause = OR2_CAUSE_BUSY_NUMBER;
- + break;
- +
- + case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
- + case AST_CAUSE_SWITCH_CONGESTION:
- + r2cause = OR2_CAUSE_NETWORK_CONGESTION;
- + break;
- +
- + case AST_CAUSE_UNALLOCATED:
- + r2cause = OR2_CAUSE_UNALLOCATED_NUMBER;
- + break;
- +
- + case AST_CAUSE_NETWORK_OUT_OF_ORDER:
- + case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
- + r2cause = OR2_CAUSE_OUT_OF_ORDER;
- + break;
- +
- + case AST_CAUSE_NO_ANSWER:
- + case AST_CAUSE_NO_USER_RESPONSE:
- + r2cause = OR2_CAUSE_NO_ANSWER;
- + break;
- +
- + default:
- + r2cause = OR2_CAUSE_NORMAL_CLEARING;
- + break;
- + }
- + ast_log(LOG_DEBUG, "dahdi_ast_cause_to_r2_cause returned %d/%s for ast cause %d\n",
- + r2cause, openr2_proto_get_disconnect_string(r2cause), cause);
- + return r2cause;
- +}
- +#endif
- static int dahdi_hangup(struct ast_channel *ast)
- {
- @@ -3129,6 +3896,27 @@
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
- /* Perform low level hangup if no owner left */
- +
- +#ifdef HAVE_OPENR2
- + if (p->mfcr2 && p->mfcr2call && openr2_chan_get_direction(p->r2chan) != OR2_DIR_STOPPED) {
- + ast_log(LOG_DEBUG, "disconnecting MFC/R2 call on chan %d\n", p->channel);
- + ast_log(LOG_DEBUG, "ast->hangupcause is %d\n", ast->hangupcause);
- + if (openr2_chan_get_direction(p->r2chan) == OR2_DIR_BACKWARD && p->mfcr2_forced_release) {
- + dahdi_r2_disconnect_call(p, OR2_CAUSE_FORCED_RELEASE);
- + } else {
- + const char *r2causestr = pbx_builtin_getvar_helper(ast,"MFCR2_CAUSE");
- + int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
- + openr2_call_disconnect_cause_t r2cause = r2cause_user
- + ? dahdi_ast_cause_to_r2_cause(r2cause_user)
- + : dahdi_ast_cause_to_r2_cause(ast->hangupcause);
- + dahdi_r2_disconnect_call(p, r2cause);
- + }
- + } else if (p->mfcr2call) {
- + ast_log(LOG_DEBUG, "Clearing call request on channel %d\n", p->channel);
- + p->mfcr2call = 0;
- + }
- +#endif
- +
- #if defined(HAVE_PRI)
- if (p->pri) {
- #ifdef SUPPORT_USERUSER
- @@ -3181,7 +3969,7 @@
- {
- p->owner = NULL;
- }
- - if (p->sig && (p->sig != SIG_PRI))
- + if (p->sig && (p->sig != SIG_PRI) && (p->sig != SIG_MFCR2))
- res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
- @@ -3364,6 +4152,26 @@
- }
- break;
- #endif
- +
- +#ifdef HAVE_OPENR2
- + case SIG_MFCR2:
- + if (!p->mfcr2_accept_on_offer) {
- + /* the call was not accepted on offer, so it must be accepted now before answering,
- + the answer will be executed when the callback on_call_accepted is executed */
- + if (p->mfcr2_charge_calls) {
- + ast_log(LOG_DEBUG, "Accepting MFC/R2 call before answering with charge on chan %d\n", p->channel);
- + openr2_chan_accept_call(p->r2chan, OR2_CALL_WITH_CHARGE);
- + } else {
- + ast_log(LOG_DEBUG, "Accepting MFC/R2 call before answering with no charge on chan %d\n", p->channel);
- + openr2_chan_accept_call(p->r2chan, OR2_CALL_NO_CHARGE);
- + }
- + } else {
- + ast_log(LOG_DEBUG, "Answering MFC/R2 call on chan %d\n", p->channel);
- + res = dahdi_r2_answer(p);
- + }
- + break;
- +#endif
- +
- case 0:
- ast_mutex_unlock(&p->lock);
- return 0;
- @@ -4133,8 +4941,6 @@
- static void *ss_thread(void *data);
- -static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
- -
- /*!
- * \internal
- * \brief Attempt to transfer 3-way call.
- @@ -4482,13 +5288,29 @@
- break;
- #endif
- case DAHDI_EVENT_BITSCHANGED:
- +#ifdef HAVE_OPENR2
- + if (p->sig != SIG_MFCR2) {
- + ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
- + } else {
- + ast_log(LOG_DEBUG, "bits changed in chan %d\n", p->channel);
- + openr2_chan_handle_cas(p->r2chan);
- + }
- +#else
- ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
- +#endif
- case DAHDI_EVENT_PULSE_START:
- /* Stop tone if there's a pulse start and the PBX isn't started */
- if (!ast->pbx)
- tone_zone_play_tone(p->subs[index].dfd, -1);
- break;
- case DAHDI_EVENT_DIALCOMPLETE:
- +#ifdef HAVE_OPENR2
- + if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
- + /* we don't need to do anything for this event for R2 signaling
- + if the call is being setup */
- + break;
- + }
- +#endif
- if (p->inalarm) break;
- if ((p->radio || (p->oprmode < 0))) break;
- if (ioctl(p->subs[index].dfd,DAHDI_DIALING,&x) == -1) {
- @@ -4572,6 +5394,12 @@
- break;
- }
- #endif
- +
- +#ifdef HAVE_OPENR2
- + if (p->sig == SIG_MFCR2)
- + break;
- +#endif
- +
- case DAHDI_EVENT_ONHOOK:
- if (p->radio) {
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- @@ -5500,6 +6328,12 @@
- else if (p->ringt > 0)
- p->ringt--;
- +#ifdef HAVE_OPENR2
- + if (p->mfcr2) {
- + openr2_chan_process_event(p->r2chan);
- + }
- +#endif
- +
- if (p->subs[index].needringing) {
- /* Send ringing frame if requested */
- p->subs[index].needringing = 0;
- @@ -5544,7 +6378,25 @@
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- }
- -
- +
- +#ifdef HAVE_OPENR2
- + if (p->mfcr2 && openr2_chan_get_read_enabled(p->r2chan)) {
- + /* openr2 took care of reading and handling any event
- + (needanswer, needbusy etc), if we continue we will read()
- + twice, lets just return a null frame. This should only
- + happen when openr2 is dialing out */
- + p->subs[index].f.frametype = AST_FRAME_NULL;
- + p->subs[index].f.subclass = 0;
- + p->subs[index].f.samples = 0;
- + p->subs[index].f.mallocd = 0;
- + p->subs[index].f.offset = 0;
- + p->subs[index].f.data = NULL;
- + p->subs[index].f.datalen= 0;
- + ast_mutex_unlock(&p->lock);
- + return &p->subs[index].f;
- + }
- +#endif
- +
- if (p->subs[index].needflash) {
- /* Send answer frame if requested */
- p->subs[index].needflash = 0;
- @@ -5862,8 +6714,15 @@
- int func = DAHDI_FLASH;
- ast_mutex_lock(&p->lock);
- index = dahdi_get_index(chan, p, 0);
- - if (option_debug)
- - ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);
- + ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);
- +#ifdef HAVE_OPENR2
- + if (p->mfcr2 && !p->mfcr2_call_accepted) {
- + ast_mutex_unlock(&p->lock);
- + /* if this an R2 call and the call is not yet accepted we don't want the
- + tone indications to mess up with the MF tones */
- + return 0;
- + }
- +#endif
- if (index == SUB_REAL) {
- switch (condition) {
- case AST_CONTROL_BUSY:
- @@ -6255,6 +7114,13 @@
- /* Configure the new channel jb */
- ast_jb_configure(tmp, &global_jbconf);
- if (startpbx) {
- +
- +#ifdef HAVE_OPENR2
- + if (i->mfcr2call) {
- + pbx_builtin_setvar_helper(tmp, "MFCR2_CATEGORY", openr2_proto_get_category_string(i->mfcr2_recvd_category));
- + }
- +#endif
- +
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- @@ -7818,7 +8684,7 @@
- count = 0;
- i = iflist;
- while (i) {
- - if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
- + if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
- if (!i->owner && !i->subs[SUB_REAL].owner) {
- /* This needs to be watched, as it lacks an owner */
- pfds[count].fd = i->subs[SUB_REAL].dfd;
- @@ -8007,6 +8873,17 @@
- return 0;
- }
- +#ifdef HAVE_OPENR2
- +static struct dahdi_mfcr2 *mfcr2_get_context(int id)
- +{
- + if ((id < 0) || (id >= (sizeof(r2links)/sizeof(r2links[0])))) {
- + ast_log(LOG_ERROR, "No more R2 links available!.\n");
- + return NULL;
- + }
- + return &r2links[id];
- +}
- +#endif
- +
- #ifdef HAVE_PRI
- static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
- {
- @@ -8358,6 +9235,92 @@
- tmp->prioffset = 0;
- }
- #endif
- +
- +#ifdef HAVE_OPENR2
- + if (chan_sig == SIG_MFCR2 && reloading != 1) {
- + char logdir[OR2_MAX_PATH];
- + struct dahdi_mfcr2 *dahdi_r2;
- + int threshold = 0;
- + int snres = 0;
- + dahdi_r2 = mfcr2_get_context(mfcr2_cur_context_index);
- + if (!dahdi_r2) {
- + ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
- + } else if (!dahdi_r2->protocol_context){
- + char tmplogdir[] = "/tmp";
- + dahdi_r2->protocol_context = openr2_context_new(NULL, &dahdi_r2_event_iface,
- + &dahdi_r2_transcode_iface, mfcr2_cur_variant, mfcr2_cur_max_ani, mfcr2_cur_max_dnis);
- + if (!dahdi_r2->protocol_context) {
- + ast_log(LOG_ERROR, "Cannot create OpenR2 protocol context.\n");
- + destroy_dahdi_pvt(&tmp);
- + return NULL;
- + }
- + openr2_context_set_log_level(dahdi_r2->protocol_context, mfcr2_cur_loglevel);
- + openr2_context_set_ani_first(dahdi_r2->protocol_context, mfcr2_cur_get_ani_first);
- + openr2_context_set_skip_category_request(dahdi_r2->protocol_context, mfcr2_cur_skip_category);
- + openr2_context_set_mf_threshold(dahdi_r2->protocol_context, threshold);
- + openr2_context_set_mf_back_timeout(dahdi_r2->protocol_context, mfcr2_cur_mfback_timeout);
- + openr2_context_set_metering_pulse_timeout(dahdi_r2->protocol_context, mfcr2_cur_metering_pulse_timeout);
- + openr2_context_set_double_answer(dahdi_r2->protocol_context, mfcr2_cur_double_answer);
- + openr2_context_set_immediate_accept(dahdi_r2->protocol_context, mfcr2_cur_immediate_accept);
- +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
- + openr2_context_set_dtmf_dialing(dahdi_r2->protocol_context, mfcr2_cur_dtmf_dialing, mfcr2_cur_dtmf_time_on, mfcr2_cur_dtmf_time_off);
- + openr2_context_set_dtmf_detection(dahdi_r2->protocol_context, mfcr2_cur_dtmf_detection);
- +#endif
- + if (ast_strlen_zero(mfcr2_cur_logdir)) {
- + if (openr2_context_set_log_directory(dahdi_r2->protocol_context, tmplogdir)) {
- + ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
- + }
- + } else {
- + snres = snprintf(logdir, sizeof(logdir), "%s/%s/%s", ast_config_AST_LOG_DIR, "mfcr2", mfcr2_cur_logdir);
- + if (snres >= sizeof(logdir)) {
- + ast_log(LOG_ERROR, "MFC/R2 logging directory truncated, using %s\n", tmplogdir);
- + if (openr2_context_set_log_directory(dahdi_r2->protocol_context, logdir)) {
- + ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
- + }
- + } else {
- + if (openr2_context_set_log_directory(dahdi_r2->protocol_context, logdir)) {
- + ast_log(LOG_ERROR, "Failed setting MFC/R2 log directory %s\n", logdir);
- + }
- + }
- + }
- + if (!ast_strlen_zero(mfcr2_cur_r2proto_file)) {
- + if (openr2_context_configure_from_advanced_file(dahdi_r2->protocol_context, mfcr2_cur_r2proto_file)) {
- + ast_log(LOG_ERROR, "Failed to configure r2context from advanced configuration file %s\n", mfcr2_cur_r2proto_file);
- + }
- + }
- + }
- + if (dahdi_r2) {
- + /* TODO: should we check numchans overflow, or is it already done by DAHDI? */
- + dahdi_r2->pvts[dahdi_r2->numchans++] = tmp;
- + tmp->r2chan = openr2_chan_new_from_fd(dahdi_r2->protocol_context,
- + tmp->subs[SUB_REAL].dfd, NULL, NULL);
- + if (!tmp->r2chan) {
- + openr2_liberr_t err = openr2_context_get_last_error(dahdi_r2->protocol_context);
- + ast_log(LOG_ERROR, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err));
- + destroy_dahdi_pvt(&tmp);
- + return NULL;
- + }
- + openr2_chan_set_client_data(tmp->r2chan, tmp);
- + /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
- + openr2_chan_set_logging_func(tmp->r2chan, (openr2_logging_func_t)dahdi_r2_on_chan_log);
- + openr2_chan_set_log_level(tmp->r2chan, mfcr2_cur_loglevel);
- + if (mfcr2_cur_call_files) {
- + openr2_chan_enable_call_files(tmp->r2chan);
- + }
- + tmp->mfcr2_category = mfcr2_cur_category;
- + tmp->mfcr2 = dahdi_r2;
- + tmp->mfcr2call = 0;
- + tmp->mfcr2block = DAHDI_R2_REMOTE_BLOCK | DAHDI_R2_LOCAL_BLOCK;
- + tmp->mfcr2_accept_on_offer = mfcr2_cur_accept_on_offer;
- + tmp->mfcr2_charge_calls = mfcr2_cur_charge_calls;
- + tmp->mfcr2_ani_index = 0;
- + tmp->mfcr2_dnis_index = 0;
- + tmp->mfcr2_allow_collect_calls = mfcr2_cur_allow_collect_calls;
- + tmp->mfcr2_forced_release = mfcr2_cur_forced_release;
- + }
- + }
- +#endif
- +
- } else {
- chan_sig = tmp->sig;
- if (tmp->subs[SUB_REAL].dfd > -1) {
- @@ -8555,7 +9518,7 @@
- ast_dsp_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
- update_conf(tmp);
- if (!here) {
- - if (chan_sig != SIG_PRI)
- + if ((chan_sig != SIG_PRI) && (chan_sig != SIG_MFCR2))
- /* Hang it up to be sure it's good */
- dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
- }
- @@ -8769,6 +9732,17 @@
- return sig_pri_available(p);
- }
- #endif
- +
- +#ifdef HAVE_OPENR2
- + /* Trust MFC/R2 */
- + if (p->mfcr2) {
- + if (p->mfcr2call || p->mfcr2block)
- + return 0;
- + else
- + return 1;
- + }
- +#endif
- +
- if (!(p->radio || (p->oprmode < 0)))
- {
- if (!p->sig || (p->sig == SIG_FXSLS))
- @@ -9076,7 +10050,26 @@
- p->pri = pri;
- }
- }
- -#endif
- +#endif
- +
- +#ifdef HAVE_OPENR2
- + if (p->mfcr2) {
- + ast_mutex_lock(&p->lock);
- + if (p->mfcr2call) {
- + ast_mutex_unlock(&p->lock);
- + ast_log(LOG_NOTICE, "Yay!, someone just beat us in the race for channel %d.\n", p->channel);
- + goto next;
- + }
- + if (p->mfcr2block) {
- + ast_mutex_unlock(&p->lock);
- + ast_log(LOG_NOTICE, "Yay!, channel %d just got blocked (%d).\n", p->channel, p->mfcr2block);
- + goto next;
- + }
- + p->mfcr2call = 1;
- + ast_mutex_unlock(&p->lock);
- + }
- +#endif
- +
- if (p->channel == CHAN_PSEUDO) {
- p = chandup(p);
- if (!p) {
- @@ -9179,6 +10172,94 @@
- return tmp;
- }
- +#ifdef HAVE_OPENR2
- +static void *mfcr2_monitor(void *data)
- +{
- + struct dahdi_pvt *p;
- + struct dahdi_mfcr2 *mfcr2 = data;
- + /* we should be using pthread_key_create
- + and allocate pollers dynamically.
- + I think do_monitor() could be leaking, since it
- + could be cancelled at any time and is not
- + using thread keys, why?, */
- + struct pollfd pollers[mfcr2->numchans];
- + int maxsleep = 20;
- + int res = 0;
- + int i = 0;
- + int pollsize = 0;
- + int oldstate = 0;
- + int was_idle = 0;
- + int quit_loop = 0;
- + /* now that we're ready to get calls, unblock our side and
- + get current line state */
- + for (i = 0; i < mfcr2->numchans; i++) {
- + p = mfcr2->pvts[i];
- + pollers[i].fd = mfcr2->pvts[i]->subs[SUB_REAL].dfd;
- + if (openr2_chan_set_idle(p->r2chan)) {
- + ast_log(LOG_ERROR, "Failed to set channel %d in IDLE\n", p->channel);
- + } else {
- + ast_mutex_lock(&p->lock);
- + mfcr2->pvts[i]->mfcr2block &= ~DAHDI_R2_LOCAL_BLOCK;
- + mfcr2->pvts[i]->mfcr2call = 0;
- + ast_mutex_unlock(&p->lock);
- + }
- + openr2_chan_handle_cas(mfcr2->pvts[i]->r2chan);
- + }
- + while(1) {
- + /* we trust here that the mfcr2 channel list will not ever change once
- + the module is loaded */
- + pollsize = 0;
- + for (i = 0; i < mfcr2->numchans; i++) {
- + pollers[i].events = 0;
- + pollers[i].revents = 0;
- + if (mfcr2->pvts[i]->owner) {
- + continue;
- + }
- + if (!mfcr2->pvts[i]->r2chan) {
- + ast_log(LOG_DEBUG, "Wow, no r2chan on channel %d\n", mfcr2->pvts[i]->channel);
- + quit_loop = 1;
- + break;
- + }
- + openr2_chan_enable_read(mfcr2->pvts[i]->r2chan);
- + pollers[i].events = POLLIN | POLLPRI;
- + pollsize++;
- + }
- + if (quit_loop) {
- + break;
- + }
- +
- + if (pollsize == 0) {
- + if (!was_idle) {
- + ast_log(LOG_NOTICE, "Monitor thread going idle since everybody has an owner\n");
- + was_idle = 1;
- + }
- + poll(NULL, 0, maxsleep);
- + continue;
- + }
- + was_idle = 0;
- +
- + /* probably poll() is a valid cancel point, lets just be on the safe side
- + by calling pthread_testcancel */
- + pthread_testcancel();
- + res = poll(pollers, mfcr2->numchans, maxsleep);
- + pthread_testcancel();
- + if ((res < 0) && (errno != EINTR)) {
- + ast_log(LOG_ERROR, "going out, poll failed: %s\n", strerror(errno));
- + break;
- + }
- + /* do we want to allow to cancel while processing events? */
- + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
- + for (i = 0; i < mfcr2->numchans; i++) {
- + if ((pollers[i].revents & POLLPRI) || (pollers[i].revents & POLLIN)) {
- + openr2_chan_process_event(mfcr2->pvts[i]->r2chan);
- + }
- + }
- + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
- + }
- + ast_log(LOG_NOTICE, "Quitting MFC/R2 monitor thread\n");
- + return 0;
- +}
- +#endif
- #if defined(HAVE_PRI)
- static struct dahdi_pvt *pri_find_crv(struct dahdi_pri *pri, int crv)
- @@ -11530,6 +12611,341 @@
- #endif /* HAVE_PRI */
- +#ifdef HAVE_OPENR2
- +
- +static int handle_mfcr2_version(int fd, int argc, char *argv[])
- +{
- + ast_cli(fd, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
- + return RESULT_SUCCESS;
- +}
- +
- +static int handle_mfcr2_show_variants(int fd, int argc, char *argv[])
- +{
- +#define FORMAT "%4s %40s\n"
- + int numvariants = 0;
- + int i;
- + const openr2_variant_entry_t *variants;
- + if (!(variants = openr2_proto_get_variant_list(&numvariants))) {
- + ast_cli(fd, "Failed to get list of variants.\n");
- + return RESULT_FAILURE;
- + }
- + ast_cli(fd, FORMAT, "Variant Code", "Country");
- + for (i = 0; i < numvariants; i++) {
- + ast_cli(fd, FORMAT, variants[i].name, variants[i].country);
- + }
- + return RESULT_SUCCESS;
- +#undef FORMAT
- +}
- +
- +static int handle_mfcr2_show_channels(int fd, int argc, char *argv[])
- +{
- +#define FORMAT "%4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
- + int filtertype = 0;
- + int targetnum = 0;
- + char channo[5];
- + char anino[5];
- + char dnisno[5];
- + struct dahdi_pvt *p;
- + openr2_context_t *r2context;
- + openr2_variant_t r2variant;
- + if (!((argc == 3) || (argc == 5))) {
- + return RESULT_SHOWUSAGE;
- + }
- + if (argc == 5) {
- + if (!strcasecmp(argv[3], "group")) {
- + targetnum = atoi(argv[4]);
- + if ((targetnum < 0) || (targetnum > 63))
- + return RESULT_SHOWUSAGE;
- + targetnum = 1 << targetnum;
- + filtertype = 1;
- + } else if (!strcasecmp(argv[3], "context")) {
- + filtertype = 2;
- + } else {
- + return RESULT_SHOWUSAGE;
- + }
- + }
- + ast_cli(fd, FORMAT, "Chan", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
- + ast_mutex_lock(&iflock);
- + p = iflist;
- + while (p) {
- + if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
- + p = p->next;
- + continue;
- + }
- + if (filtertype) {
- + switch(filtertype) {
- + case 1: /* mfcr2 show channels group <group> */
- + if (p->group != targetnum) {
- + p = p->next;
- + continue;
- + }
- + break;
- + case 2: /* mfcr2 show channels context <context> */
- + if (strcasecmp(p->context, argv[4])) {
- + p= p->next;
- + continue;
- + }
- + break;
- + default:
- + ;
- + }
- + }
- + r2context = openr2_chan_get_context(p->r2chan);
- + r2variant = openr2_context_get_variant(r2context);
- + snprintf(channo, sizeof(channo), "%d", p->channel);
- + snprintf(anino, sizeof(anino), "%d", openr2_context_get_max_ani(r2context));
- + snprintf(dnisno, sizeof(dnisno), "%d", openr2_context_get_max_dnis(r2context));
- + ast_cli(fd, FORMAT, channo, openr2_proto_get_variant_string(r2variant),
- + anino, dnisno, openr2_context_get_ani_first(r2context) ? "Yes" : "No",
- + openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
- + openr2_chan_get_tx_cas_string(p->r2chan), openr2_chan_get_rx_cas_string(p->r2chan));
- + p = p->next;
- + }
- + ast_mutex_unlock(&iflock);
- + return RESULT_SUCCESS;
- +#undef FORMAT
- +}
- +
- +static int handle_mfcr2_set_debug(int fd, int argc, char *argv[])
- +{
- + struct dahdi_pvt *p = NULL;
- + int channo = 0;
- + char *toklevel = NULL;
- + char *saveptr = NULL;
- + char *logval = NULL;
- + openr2_log_level_t loglevel = OR2_LOG_NOTHING;
- + openr2_log_level_t tmplevel = OR2_LOG_NOTHING;
- + if (argc < 4) {
- + return RESULT_SHOWUSAGE;
- + }
- + channo = (argc == 5) ? atoi(argv[4]) : -1;
- + logval = ast_strdupa(argv[3]);
- + toklevel = strtok_r(logval, ",", &saveptr);
- + if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
- + ast_cli(fd, "Invalid MFC/R2 logging level '%s'.\n", argv[3]);
- + return RESULT_FAILURE;
- + } else if (OR2_LOG_NOTHING == tmplevel) {
- + loglevel = tmplevel;
- + } else {
- + loglevel |= tmplevel;
- + while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
- + if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
- + ast_cli(fd, "Ignoring invalid logging level: '%s'.\n", toklevel);
- + continue;
- + }
- + loglevel |= tmplevel;
- + }
- + }
- + ast_mutex_lock(&iflock);
- + p = iflist;
- + while (p) {
- + if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
- + p = p->next;
- + continue;
- + }
- + if ((channo != -1) && (p->channel != channo )) {
- + p = p->next;
- + continue;
- + }
- + openr2_chan_set_log_level(p->r2chan, loglevel);
- + if (channo != -1) {
- + ast_cli(fd, "MFC/R2 debugging set to '%s' for channel %d.\n", argv[3], p->channel);
- + break;
- + } else {
- + p = p->next;
- + }
- + }
- + if ((channo != -1) && !p) {
- + ast_cli(fd, "MFC/R2 channel %d not found.\n", channo);
- + }
- + if (channo == -1) {
- + ast_cli(fd, "MFC/R2 debugging set to '%s' for all channels.\n", argv[3]);
- + }
- + ast_mutex_unlock(&iflock);
- + return RESULT_SUCCESS;
- +}
- +
- +static int handle_mfcr2_call_files(int fd, int argc, char *argv[])
- +{
- + struct dahdi_pvt *p = NULL;
- + int channo = 0;
- + if (argc < 4) {
- + return RESULT_SHOWUSAGE;
- + }
- + channo = (argc == 5) ? atoi(argv[4]) : -1;
- + ast_mutex_lock(&iflock);
- + p = iflist;
- + while (p) {
- + if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
- + p = p->next;
- + continue;
- + }
- + if ((channo != -1) && (p->channel != channo )) {
- + p = p->next;
- + continue;
- + }
- + if (ast_true(argv[3])) {
- + openr2_chan_enable_call_files(p->r2chan);
- + } else {
- + openr2_chan_disable_call_files(p->r2chan);
- + }
- + if (channo != -1) {
- + if (ast_true(argv[3])) {
- + ast_cli(fd, "MFC/R2 call files enabled for channel %d.\n", p->channel);
- + } else {
- + ast_cli(fd, "MFC/R2 call files disabled for channel %d.\n", p->channel);
- + }
- + break;
- + } else {
- + p = p->next;
- + }
- + }
- + if ((channo != -1) && !p) {
- + ast_cli(fd, "MFC/R2 channel %d not found.\n", channo);
- + }
- + if (channo == -1) {
- + if (ast_true(argv[3])) {
- + ast_cli(fd, "MFC/R2 Call files enabled for all channels.\n");
- + } else {
- + ast_cli(fd, "MFC/R2 Call files disabled for all channels.\n");
- + }
- + }
- + ast_mutex_unlock(&iflock);
- + return RESULT_SUCCESS;
- +}
- +
- +static int handle_mfcr2_set_idle(int fd, int argc, char *argv[])
- +{
- + struct dahdi_pvt *p = NULL;
- + int channo = 0;
- + channo = (argc == 4) ? atoi(argv[3]) : -1;
- + ast_mutex_lock(&iflock);
- + p = iflist;
- + while (p) {
- + if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
- + p = p->next;
- + continue;
- + }
- + if ((channo != -1) && (p->channel != channo )) {
- + p = p->next;
- + continue;
- + }
- + if (!openr2_chan_set_idle(p->r2chan)) {
- + ast_mutex_lock(&p->lock);
- + p->mfcr2call = 0;
- + p->mfcr2block &= ~DAHDI_R2_LOCAL_BLOCK;
- + ast_mutex_unlock(&p->lock);
- + }
- + if (channo != -1) {
- + break;
- + } else {
- + p = p->next;
- + }
- + }
- + if ((channo != -1) && !p) {
- + ast_cli(fd, "MFC/R2 channel %d not found.\n", channo);
- + }
- + ast_mutex_unlock(&iflock);
- + return RESULT_SUCCESS;
- +}
- +
- +static int handle_mfcr2_set_blocked(int fd, int argc, char *argv[])
- +{
- + struct dahdi_pvt *p = NULL;
- + int channo = 0;
- + channo = (argc == 4) ? atoi(argv[3]) : -1;
- + ast_mutex_lock(&iflock);
- + p = iflist;
- + while (p) {
- + if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
- + p = p->next;
- + continue;
- + }
- + if ((channo != -1) && (p->channel != channo )) {
- + p = p->next;
- + continue;
- + }
- + if (!openr2_chan_set_blocked(p->r2chan)) {
- + ast_mutex_lock(&p->lock);
- + p->mfcr2block |= DAHDI_R2_LOCAL_BLOCK;
- + ast_mutex_unlock(&p->lock);
- + } else {
- + ast_cli(fd, "MFC/R2 channel %d could not be blocked.\n", p->channel);
- + }
- + if (channo != -1) {
- + break;
- + } else {
- + p = p->next;
- + }
- + }
- + if ((channo != -1) && !p) {
- + ast_cli(fd, "MFC/R2 channel %d not found.\n", channo);
- + }
- + ast_mutex_unlock(&iflock);
- + return RESULT_SUCCESS;
- +}
- +
- +static const char dahdi_r2_version_help[] =
- + "Usage: mfcr2 show version\n"
- + " Shows the version of the OpenR2 library being used.\n";
- +static const char dahdi_r2_variants_help[] =
- + "Usage: mfcr2 show variants\n"
- + " Show supported MFC/R2 variants.\n";
- +static const char dahdi_r2_showchannels_help[] =
- + "Usage: mfcr2 show channels [group <group> | context <context>]\n"
- + " Shows the zap channels configured with MFC/R2 signaling.\n";
- +static const char dahdi_r2_setdebug_help[] =
- + "Usage: mfcr2 set debug <loglevel> <channel>\n"
- + " Set a new logging level for the specified channel.\n"
- + " If no channel is specified the logging level will be applied to all channels.\n";
- +static const char dahdi_r2_callfiles_help[] =
- + "Usage: mfcr2 call files [on|off] <channel>\n"
- + " Enable call files creation on the specified channel.\n"
- + " If no channel is specified call files creation policy will be applied to all channels.\n";
- +static const char dahdi_r2_setidle_help[] =
- + "Usage: mfcr2 set idle <channel>\n"
- + " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
- + " Force the given channel into IDLE state.\n"
- + " If no channel is specified, all channels will be set to IDLE.\n";
- +static const char dahdi_r2_setblocked_help[] =
- + "Usage: mfcr2 set blocked <channel>\n"
- + " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
- + " Force the given channel into BLOCKED state.\n"
- + " If no channel is specified, all channels will be set to BLOCKED.\n";
- +
- +static struct ast_cli_entry dahdi_mfcr2_cli[] = {
- + { { "mfcr2", "show", "version", NULL },
- + handle_mfcr2_version, "Show OpenR2 library version",
- + dahdi_r2_version_help },
- +
- + { { "mfcr2", "show", "variants", NULL },
- + handle_mfcr2_show_variants, "Show supported MFC/R2 variants",
- + dahdi_r2_variants_help },
- +
- + { { "mfcr2", "show", "channels", NULL },
- + handle_mfcr2_show_channels, "Show MFC/R2 channels",
- + dahdi_r2_showchannels_help },
- +
- + { { "mfcr2", "set", "debug", NULL },
- + handle_mfcr2_set_debug, "Set MFC/R2 channel logging level",
- + dahdi_r2_setdebug_help },
- +
- + { { "mfcr2", "call", "files", NULL },
- + handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files",
- + dahdi_r2_callfiles_help },
- +
- + { { "mfcr2", "set", "idle", NULL },
- + handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE",
- + dahdi_r2_setidle_help },
- +
- + { { "mfcr2", "set", "blocked", NULL },
- + handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED",
- + dahdi_r2_setblocked_help }
- +
- +};
- +
- +#endif /* HAVE_OPENR2 */
- +
- static int dahdi_destroy_channel(int fd, int argc, char **argv)
- {
- int channel;
- @@ -11573,6 +12989,11 @@
- static int setup_dahdi(int reload);
- static int dahdi_restart(void)
- {
- +
- +#ifdef HAVE_OPENR2
- + int r;
- +#endif
- +
- #if defined(HAVE_PRI)
- int i, j;
- #endif
- @@ -11587,6 +13008,18 @@
- if (option_verbose > 3)
- ast_verbose("Initial softhangup of all DAHDI channels complete.\n");
- +#ifdef HAVE_OPENR2
- + for (r = 0; r < NUM_SPANS; r++) {
- + if (r2links[r].master != AST_PTHREADT_NULL) {
- + ast_log(LOG_DEBUG, "Killing MFC/R2 monitor thread %p\n", &r2links[r].master);
- + pthread_cancel(r2links[r].master);
- + pthread_join(r2links[r].master, NULL);
- + openr2_context_delete(r2links[r].protocol_context);
- + }
- + }
- + init_mfcr2_globals();
- +#endif
- +
- #if defined(HAVE_PRI)
- for (i = 0; i < NUM_SPANS; i++) {
- if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) {
- @@ -11821,6 +13254,43 @@
- if (tmp->slaves[x])
- ast_cli(fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
- }
- +
- +#ifdef HAVE_OPENR2
- + if (tmp->mfcr2) {
- + char calldir[OR2_MAX_PATH];
- + openr2_context_t *r2context = openr2_chan_get_context(tmp->r2chan);
- + openr2_variant_t r2variant = openr2_context_get_variant(r2context);
- + ast_cli(fd, "MFC/R2 Call: %s\n", tmp->mfcr2call ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 Blocked: %s\n", tmp->mfcr2block ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp->r2chan));
- + ast_cli(fd, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp->r2chan));
- + ast_cli(fd, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp->r2chan));
- + ast_cli(fd, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp->r2chan));
- + ast_cli(fd, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp->r2chan) ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant));
- + ast_cli(fd, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context));
- + ast_cli(fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
- +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
- + ast_cli(fd, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context, NULL, NULL) ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context) ? "Yes" : "No");
- +#endif
- + ast_cli(fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 Skip Category: %s\n", openr2_context_get_skip_category_request(r2context) ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 Accept On Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 Allow Collect Calls: %s\n", tmp->mfcr2_allow_collect_calls ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 Forced Release: %s\n", tmp->mfcr2_forced_release ? "Yes" : "No");
- + ast_cli(fd, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context));
- + ast_cli(fd, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context));
- + ast_cli(fd, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp->r2chan));
- + ast_cli(fd, "MFC/R2 Tx CAS : %s\n", openr2_chan_get_tx_cas_string(tmp->r2chan));
- + ast_cli(fd, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp->r2chan));
- + ast_cli(fd, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp->r2chan));
- + ast_cli(fd, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context, calldir, sizeof(calldir)));
- + }
- +#endif
- +
- #ifdef HAVE_PRI
- if (tmp->pri) {
- ast_cli(fd, "PRI Flags: ");
- @@ -12303,6 +13773,10 @@
- {
- struct dahdi_pvt *p;
- +#ifdef HAVE_OPENR2
- + int r;
- +#endif
- +
- #ifdef HAVE_PRI
- int i, j;
- for (i = 0; i < NUM_SPANS; i++) {
- @@ -12316,6 +13790,21 @@
- }
- ast_unregister_application(zap_send_keypad_facility_app);
- #endif
- +
- +#ifdef HAVE_OPENR2
- + for (r = 0; r < NUM_SPANS; r++) {
- + if (r2links[r].master != AST_PTHREADT_NULL) {
- + pthread_cancel(r2links[r].master);
- + pthread_join(r2links[r].master, NULL);
- + }
- + }
- + ast_cli_unregister_multiple(dahdi_mfcr2_cli, sizeof(dahdi_mfcr2_cli) / sizeof(dahdi_mfcr2_cli[0]));
- + if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
- + ast_unregister_application(dahdi_accept_r2_call_app);
- + }
- + ast_unregister_application(zap_accept_r2_call_app);
- +#endif
- +
- ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
- local_astman_unregister("DialOffHook");
- local_astman_unregister("Hangup");
- @@ -12353,6 +13842,15 @@
- }
- }
- #endif
- +
- +#ifdef HAVE_OPENR2
- + for (r = 0; r < NUM_SPANS; r++) {
- + if (r2links[r].protocol_context) {
- + openr2_context_delete(r2links[r].protocol_context);
- + }
- + }
- +#endif
- +
- ast_cond_destroy(&ss_thread_complete);
- return 0;
- }
- @@ -12452,6 +13950,13 @@
- return -1;
- }
- }
- +
- +#ifdef HAVE_OPENR2
- + if (reload != 1 && r2links[mfcr2_cur_context_index].protocol_context) {
- + mfcr2_cur_context_index++;
- + }
- +#endif
- +
- }
- return 0;
- @@ -12796,6 +14301,11 @@
- } else if (!strcasecmp(v->value, "featb")) {
- confp->chan.sig = SIG_FEATB;
- confp->chan.radio = 0;
- +#ifdef HAVE_OPENR2
- + } else if (!strcasecmp(v->value, "mfcr2")) {
- + confp->chan.sig = SIG_MFCR2;
- +#endif
- +
- #ifdef HAVE_PRI
- } else if (!strcasecmp(v->value, "pri_net")) {
- confp->chan.radio = 0;
- @@ -13006,6 +14516,98 @@
- } else if (!strcasecmp(v->name, "facilityenable")) {
- confp->pri.facilityenable = ast_true(v->value);
- #endif /* HAVE_PRI */
- +
- +#ifdef HAVE_OPENR2
- + } else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
- + ast_copy_string(mfcr2_cur_r2proto_file, v->value, sizeof(mfcr2_cur_r2proto_file));
- + ast_log(LOG_WARNING, "MFC/R2 Protocol file '%s' will be used, you only should use this if you *REALLY KNOW WHAT YOU ARE DOING*.\n", mfcr2_cur_r2proto_file);
- + } else if (!strcasecmp(v->name, "mfcr2_logdir")) {
- + ast_copy_string(mfcr2_cur_logdir, v->value, sizeof(mfcr2_cur_logdir));
- + } else if (!strcasecmp(v->name, "mfcr2_variant")) {
- + mfcr2_cur_variant = openr2_proto_get_variant(v->value);
- + if (OR2_VAR_UNKNOWN == mfcr2_cur_variant) {
- + ast_log(LOG_WARNING, "Unknown MFC/R2 variant '%s' at line %d.\n", v->value, v->lineno);
- + }
- + } else if (!strcasecmp(v->name, "mfcr2_mfback_timeout")) {
- + mfcr2_cur_mfback_timeout = atoi(v->value);
- + if (!mfcr2_cur_mfback_timeout) {
- + ast_log(LOG_WARNING, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
- + mfcr2_cur_mfback_timeout = -1;
- + } else if (mfcr2_cur_mfback_timeout > 0 && mfcr2_cur_mfback_timeout < 500) {
- + ast_log(LOG_WARNING, "MF timeout less than 500ms is not recommended, you have been warned!\n");
- + }
- + } else if (!strcasecmp(v->name, "mfcr2_metering_pulse_timeout")) {
- + mfcr2_cur_metering_pulse_timeout = atoi(v->value);
- + if (mfcr2_cur_metering_pulse_timeout > 500) {
- + ast_log(LOG_WARNING, "mfcr2_metering_pulse_timeout greater than 500ms is not recommended, you have been warned!\n");
- + }
- +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
- + } else if (!strcasecmp(v->name, "mfcr2_dtmf_detection")) {
- + mfcr2_cur_dtmf_detection = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_dtmf_dialing")) {
- + mfcr2_cur_dtmf_dialing = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_on")) {
- + mfcr2_cur_dtmf_time_on = atoi(v->value);
- + } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_off")) {
- + mfcr2_cur_dtmf_time_off = atoi(v->value);
- +#endif
- + } else if (!strcasecmp(v->name, "mfcr2_get_ani_first")) {
- + mfcr2_cur_get_ani_first = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_skip_category")) {
- + mfcr2_cur_skip_category = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_double_answer")) {
- + mfcr2_cur_double_answer = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_accept_on_offer")) {
- + mfcr2_cur_accept_on_offer = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_charge_calls")) {
- + mfcr2_cur_charge_calls = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_allow_collect_calls")) {
- + mfcr2_cur_allow_collect_calls = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_forced_release")) {
- + mfcr2_cur_forced_release= ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_immediate_accept")) {
- + mfcr2_cur_immediate_accept = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_call_files")) {
- + mfcr2_cur_call_files = ast_true(v->value) ? 1 : 0;
- + } else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
- + mfcr2_cur_max_ani = atoi(v->value);
- + if (mfcr2_cur_max_ani >= AST_MAX_EXTENSION) {
- + mfcr2_cur_max_ani = AST_MAX_EXTENSION - 1;
- + }
- + } else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
- + mfcr2_cur_max_dnis = atoi(v->value);
- + if (mfcr2_cur_max_dnis >= AST_MAX_EXTENSION) {
- + mfcr2_cur_max_dnis = AST_MAX_EXTENSION - 1;
- + }
- + } else if (!strcasecmp(v->name, "mfcr2_category")) {
- + mfcr2_cur_category = openr2_proto_get_category(v->value);
- + if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN == mfcr2_cur_category) {
- + mfcr2_cur_category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
- + ast_log(LOG_WARNING, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
- + v->value, v->lineno);
- + }
- + } else if (!strcasecmp(v->name, "mfcr2_logging")) {
- + openr2_log_level_t tmplevel;
- + char *toklevel = NULL;
- + char *saveptr = NULL;
- + char *logval = ast_strdupa(v->value);
- + toklevel = strtok_r(logval, ",", &saveptr);
- + if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
- + ast_log(LOG_WARNING, "Invalid MFC/R2 logging level '%s' at line %d.\n", v->value, v->lineno);
- + } else if (OR2_LOG_NOTHING == tmplevel) {
- + mfcr2_cur_loglevel = tmplevel;
- + } else {
- + mfcr2_cur_loglevel |= tmplevel;
- + while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
- + if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
- + ast_log(LOG_WARNING, "Ignoring invalid logging level: '%s' at line %d.\n", toklevel, v->lineno);
- + continue;
- + }
- + mfcr2_cur_loglevel |= tmplevel;
- + }
- + }
- +#endif /* HAVE_OPENR2 */
- +
- } else if (!strcasecmp(v->name, "cadence")) {
- /* setup to scan our argument */
- int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- @@ -13305,6 +14907,23 @@
- }
- }
- #endif
- +
- +#ifdef HAVE_OPENR2
- + if (reload != 1) {
- + int x;
- + for (x = 0; x < NUM_SPANS; x++) {
- + if (r2links[x].protocol_context) {
- + if (ast_pthread_create(&r2links[x].master, NULL, mfcr2_monitor, &r2links[x])) {
- + ast_log(LOG_ERROR, "Unable to start R2 context on span %d\n", x + 1);
- + return -1;
- + } else {
- + ast_verbose(VERBOSE_PREFIX_2 "Starting R2 context on span %d\n", x + 1);
- + }
- + }
- + }
- + }
- +#endif
- +
- /* And start the monitor for the first time */
- restart_monitor();
- return 0;
- @@ -13340,6 +14959,17 @@
- ast_register_application(zap_send_keypad_facility_app, zap_send_keypad_facility_exec,
- zap_send_keypad_facility_synopsis, zap_send_keypad_facility_descrip);
- #endif
- +
- +#ifdef HAVE_OPENR2
- + init_mfcr2_globals();
- + if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
- + ast_register_application(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec,
- + dahdi_accept_r2_call_synopsis, dahdi_accept_r2_call_descrip);
- + }
- + ast_register_application(zap_accept_r2_call_app, zap_accept_r2_call_exec,
- + zap_accept_r2_call_synopsis, zap_accept_r2_call_descrip);
- +#endif
- +
- if ((res = setup_dahdi(0))) {
- return AST_MODULE_LOAD_DECLINE;
- }
- @@ -13358,6 +14988,11 @@
- ast_string_field_set(&inuse, name, "GR-303InUse");
- ast_cli_register_multiple(dahdi_pri_cli, sizeof(dahdi_pri_cli) / sizeof(struct ast_cli_entry));
- #endif
- +
- +#ifdef HAVE_OPENR2
- + ast_cli_register_multiple(dahdi_mfcr2_cli, sizeof(dahdi_mfcr2_cli)/sizeof(dahdi_mfcr2_cli[0]));
- +#endif
- +
- ast_cli_register_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
- memset(round_robin, 0, sizeof(round_robin));
- ===================================================================
- Index: configure.ac
- ===================================================================
- --- configure.ac 2011-05-02 15:25:07.000000000 -0300
- +++ configure.ac 2011-06-30 16:34:15.000000000 -0300
- @@ -266,6 +266,7 @@
- AST_EXT_LIB_SETUP_DEPENDENT([PRI_CALL_HOLD], [NOTIFY with call ptr], [PRI], [pri])
- AST_EXT_LIB_SETUP_DEPENDENT([PRI_VERSION], [ISDN PRI get_version], [PRI], [pri])
- AST_EXT_LIB_SETUP_DEPENDENT([PRI_INBANDDISCONNECT], [ISDN PRI set_inbanddisconnect], [PRI], [pri])
- +AST_EXT_LIB_SETUP([OPENR2], [MFCR2], [openr2])
- AST_EXT_LIB_SETUP([PWLIB], [PWlib], [pwlib])
- AST_EXT_LIB_SETUP([RADIUS], [Radius Client], [radius])
- AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex])
- @@ -1487,6 +1488,7 @@
- AST_EXT_LIB_CHECK([PRI_CALL_HOLD], [pri], [pri_hold_enable], [libpri.h])
- AST_EXT_LIB_CHECK([PRI_VERSION], [pri], [pri_get_version], [libpri.h])
- AST_EXT_LIB_CHECK([PRI_INBANDDISCONNECT], [pri], [pri_set_inbanddisconnect], [libpri.h])
- +AST_EXT_LIB_CHECK([OPENR2], [openr2], [openr2_chan_new], [openr2.h])
- if test "${USE_PWLIB}" != "no"; then
- if test -n "${PWLIB_DIR}"; then
- ===================================================================
- Index: include/asterisk/dahdi_compat.h
- ===================================================================
- --- include/asterisk/dahdi_compat.h 2009-02-13 19:53:16.000000000 -0200
- +++ include/asterisk/dahdi_compat.h 2011-06-30 16:35:47.000000000 -0300
- @@ -320,6 +320,9 @@
- #if defined(ZT_SETTONEZONE)
- #define DAHDI_SETTONEZONE ZT_SETTONEZONE
- #endif
- +#if defined(ZT_SIG_CAS)
- +#define DAHDI_SIG_CAS ZT_SIG_CAS
- +#endif
- #if defined(ZT_SIG_CLEAR)
- #define DAHDI_SIG_CLEAR ZT_SIG_CLEAR
- #endif
- ===================================================================
- Index: makeopts.in
- ===================================================================
- --- makeopts.in 2010-12-17 19:40:56.000000000 -0200
- +++ makeopts.in 2011-06-30 16:36:39.000000000 -0300
- @@ -141,6 +141,9 @@
- PRI_INCLUDE=@PRI_INCLUDE@
- PRI_LIB=@PRI_LIB@
- +OPENR2_INCLUDE=@OPENR2_INCLUDE@
- +OPENR2_LIB=@OPENR2_LIB@
- +
- PWLIB_INCLUDE=@PWLIB_INCLUDE@
- PWLIB_LIB=@PWLIB_LIB@
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement