Newer
Older
ast_free(ast_channel_dialed(chan)->number.str);
ast_channel_dialed(chan)->number.str = ast_strdup(exten);
if (p->pri->append_msn_to_user_tag && p->pri->nodetype != PRI_NETWORK) {
/*
* Update the user tag for party id's from this device for this call
* now that we have a complete MSN from the network.
*/
snprintf(p->user_tag, sizeof(p->user_tag), "%s_%s", p->pri->initial_user_tag,
exten);
ast_free(ast_channel_caller(chan)->id.tag);
ast_channel_caller(chan)->id.tag = ast_strdup(p->user_tag);
}
}
sig_pri_play_tone(p, -1);
if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
/* Start the real PBX */
ast_channel_exten_set(chan, exten);
sig_pri_dsp_reset_and_flush_digits(p);
#if defined(ISSUE_16789)
/*
* Conditionaled out this code to effectively revert the Mantis
* issue 16789 change. It breaks overlap dialing through
* Asterisk. There is not enough information available at this
* point to know if dialing is complete. The
* ast_exists_extension(), ast_matchmore_extension(), and
* ast_canmatch_extension() calls are not adequate to detect a
* dial through extension pattern of "_9!".
*
* Workaround is to use the dialplan Proceeding() application
* early on non-dial through extensions.
*/
if ((p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
&& !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
pri_grab(p, p->pri);
if (p->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING) {
p->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
}
pri_proceeding(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 0);
pri_rel(p->pri);
}
}
#endif /* defined(ISSUE_16789) */
sig_pri_set_echocanceller(p, 1);
ast_setstate(chan, AST_STATE_RING);
res = ast_pbx_run(chan);
if (res) {
ast_log(LOG_WARNING, "PBX exited non-zero!\n");
}
} else {
ast_debug(1, "No such possible extension '%s' in context '%s'\n", exten, ast_channel_context(chan));
ast_channel_hangupcause_set(chan, AST_CAUSE_UNALLOCATED);
ast_hangup(chan);
p->exten[0] = '\0';
/* Since we send release complete here, we won't get one */
p->call = NULL;
ast_mutex_lock(&p->pri->lock);
sig_pri_span_devstate_changed(p->pri);
ast_mutex_unlock(&p->pri->lock);
}
return NULL;
}
void pri_event_alarm(struct sig_pri_span *pri, int index, int before_start_pri)
{
pri->dchanavail[index] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
if (!before_start_pri) {
pri_find_dchan(pri);
void pri_event_noalarm(struct sig_pri_span *pri, int index, int before_start_pri)
{
pri->dchanavail[index] |= DCHAN_NOTINALARM;
if (!before_start_pri)
pri_restart(pri->dchans[index]);
}
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
/*!
* \internal
* \brief Convert libpri party name into asterisk party name.
* \since 1.8
*
* \param ast_name Asterisk party name structure to fill. Must already be set initialized.
* \param pri_name libpri party name structure containing source information.
*
* \note The filled in ast_name structure needs to be destroyed by
* ast_party_name_free() when it is no longer needed.
*
* \return Nothing
*/
static void sig_pri_party_name_convert(struct ast_party_name *ast_name, const struct pri_party_name *pri_name)
{
ast_name->str = ast_strdup(pri_name->str);
ast_name->char_set = pri_to_ast_char_set(pri_name->char_set);
ast_name->presentation = pri_to_ast_presentation(pri_name->presentation);
ast_name->valid = 1;
}
/*!
* \internal
* \brief Convert libpri party number into asterisk party number.
* \since 1.8
*
* \param ast_number Asterisk party number structure to fill. Must already be set initialized.
* \param pri_number libpri party number structure containing source information.
* \param pri PRI span control structure.
*
* \note The filled in ast_number structure needs to be destroyed by
* ast_party_number_free() when it is no longer needed.
*
* \return Nothing
*/
static void sig_pri_party_number_convert(struct ast_party_number *ast_number, const struct pri_party_number *pri_number, struct sig_pri_span *pri)
{
char number[AST_MAX_EXTENSION];
apply_plan_to_existing_number(number, sizeof(number), pri, pri_number->str,
pri_number->plan);
ast_number->str = ast_strdup(number);
ast_number->plan = pri_number->plan;
ast_number->presentation = pri_to_ast_presentation(pri_number->presentation);
ast_number->valid = 1;
}
/*!
* \internal
* \brief Convert libpri party id into asterisk party id.
Kevin P. Fleming
committed
* \since 1.8
*
* \param ast_id Asterisk party id structure to fill. Must already be set initialized.
* \param pri_id libpri party id structure containing source information.
* \param pri PRI span control structure.
*
* \note The filled in ast_id structure needs to be destroyed by
* ast_party_id_free() when it is no longer needed.
*
* \return Nothing
*/
static void sig_pri_party_id_convert(struct ast_party_id *ast_id, const struct pri_party_id *pri_id, struct sig_pri_span *pri)
{
if (pri_id->name.valid) {
sig_pri_party_name_convert(&ast_id->name, &pri_id->name);
}
if (pri_id->number.valid) {
sig_pri_party_number_convert(&ast_id->number, &pri_id->number, pri);
Richard Mudgett
committed
#if defined(HAVE_PRI_SUBADDR)
if (pri_id->subaddress.valid) {
sig_pri_set_subaddress(&ast_id->subaddress, &pri_id->subaddress);
}
#endif /* defined(HAVE_PRI_SUBADDR) */
}
/*!
* \internal
* \brief Convert libpri redirecting information into asterisk redirecting information.
Kevin P. Fleming
committed
* \since 1.8
*
* \param ast_redirecting Asterisk redirecting structure to fill.
* \param pri_redirecting libpri redirecting structure containing source information.
* \param ast_guide Asterisk redirecting structure to use as an initialization guide.
* \param pri PRI span control structure.
*
* \note The filled in ast_redirecting structure needs to be destroyed by
* ast_party_redirecting_free() when it is no longer needed.
*
* \return Nothing
*/
static void sig_pri_redirecting_convert(struct ast_party_redirecting *ast_redirecting,
const struct pri_party_redirecting *pri_redirecting,
const struct ast_party_redirecting *ast_guide,
struct sig_pri_span *pri)
{
ast_party_redirecting_set_init(ast_redirecting, ast_guide);
sig_pri_party_id_convert(&ast_redirecting->orig, &pri_redirecting->orig_called, pri);
sig_pri_party_id_convert(&ast_redirecting->from, &pri_redirecting->from, pri);
sig_pri_party_id_convert(&ast_redirecting->to, &pri_redirecting->to, pri);
ast_redirecting->count = pri_redirecting->count;
ast_redirecting->reason = pri_to_ast_reason(pri_redirecting->reason);
ast_redirecting->orig_reason = pri_to_ast_reason(pri_redirecting->orig_reason);
Richard Mudgett
committed
/*!
* \internal
* \brief Determine if the given extension matches one of the MSNs in the pattern list.
Kevin P. Fleming
committed
* \since 1.8
Richard Mudgett
committed
*
* \param msn_patterns Comma separated list of MSN patterns to match.
* \param exten Extension to match in the MSN list.
*
* \retval 1 if matches.
* \retval 0 if no match.
*/
static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
{
char *pattern;
char *msn_list;
char *list_tail;
msn_list = ast_strdupa(msn_patterns);
Richard Mudgett
committed
list_tail = NULL;
pattern = strtok_r(msn_list, ",", &list_tail);
while (pattern) {
pattern = ast_strip(pattern);
if (!ast_strlen_zero(pattern) && ast_extension_match(pattern, exten)) {
/* Extension matched the pattern. */
return 1;
}
pattern = strtok_r(NULL, ",", &list_tail);
}
/* Did not match any pattern in the list. */
return 0;
}
#if defined(HAVE_PRI_MCID)
/*!
* \internal
* \brief Append the given party id to the event string.
* \since 1.8
*
* \param msg Event message string being built.
* \param prefix Prefix to add to the party id lines.
* \param party Party information to encode.
*
* \return Nothing
*/
static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, struct ast_party_id *party)
{
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
int pres;
/* Combined party presentation */
pres = ast_party_id_presentation(party);
ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix, pres,
ast_describe_caller_presentation(pres));
/* Party number */
ast_str_append(msg, 0, "%sNumValid: %d\r\n", prefix,
(unsigned) party->number.valid);
ast_str_append(msg, 0, "%sNum: %s\r\n", prefix,
S_COR(party->number.valid, party->number.str, ""));
ast_str_append(msg, 0, "%ston: %d\r\n", prefix, party->number.plan);
if (party->number.valid) {
ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, party->number.plan);
ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix,
party->number.presentation,
ast_describe_caller_presentation(party->number.presentation));
}
/* Party name */
ast_str_append(msg, 0, "%sNameValid: %d\r\n", prefix,
(unsigned) party->name.valid);
ast_str_append(msg, 0, "%sName: %s\r\n", prefix,
S_COR(party->name.valid, party->name.str, ""));
if (party->name.valid) {
ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix,
ast_party_name_charset_describe(party->name.char_set));
ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix,
party->name.presentation,
ast_describe_caller_presentation(party->name.presentation));
}
if (party->subaddress.valid) {
static const char subaddress[] = "Subaddr";
ast_str_append(msg, 0, "%s%s: %s\r\n", prefix, subaddress,
S_OR(party->subaddress.str, ""));
ast_str_append(msg, 0, "%s%sType: %d\r\n", prefix, subaddress,
party->subaddress.type);
ast_str_append(msg, 0, "%s%sOdd: %d\r\n", prefix, subaddress,
party->subaddress.odd_even_indicator);
}
#endif /* defined(HAVE_PRI_SUBADDR) */
}
#endif /* defined(HAVE_PRI_MCID) */
#if defined(HAVE_PRI_MCID)
/*!
* \internal
* \brief Handle the MCID event.
* \since 1.8
*
* \param pri PRI span control structure.
* \param mcid MCID event parameters.
* \param owner Asterisk channel associated with the call.
* NULL if Asterisk no longer has the ast_channel struct.
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the owner channel lock is already obtained if still present.
*
* \return Nothing
*/
static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd_mcid_req *mcid, struct ast_channel *owner)
{
struct ast_channel *chans[1];
struct ast_str *msg;
struct ast_party_id party;
msg = ast_str_create(4096);
if (!msg) {
return;
}
if (owner) {
/*
* The owner channel is present.
* Pass the event to the peer as well.
*/
ast_queue_control(owner, AST_CONTROL_MCID);
ast_str_append(&msg, 0, "Channel: %s\r\n", ast_channel_name(owner));
ast_str_append(&msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(owner));
sig_pri_event_party_id(&msg, "CallerID", &ast_channel_connected(owner)->id);
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
} else {
/*
* Since we no longer have an owner channel,
* we have to use the caller information supplied by libpri.
*/
ast_party_id_init(&party);
sig_pri_party_id_convert(&party, &mcid->originator, pri);
sig_pri_event_party_id(&msg, "CallerID", &party);
ast_party_id_free(&party);
}
/* Always use libpri's called party information. */
ast_party_id_init(&party);
sig_pri_party_id_convert(&party, &mcid->answerer, pri);
sig_pri_event_party_id(&msg, "ConnectedID", &party);
ast_party_id_free(&party);
chans[0] = owner;
ast_manager_event_multichan(EVENT_FLAG_CALL, "MCID", owner ? 1 : 0, chans, "%s",
ast_str_buffer(msg));
ast_free(msg);
}
#endif /* defined(HAVE_PRI_MCID) */
#if defined(HAVE_PRI_TRANSFER)
struct xfer_rsp_data {
struct sig_pri_span *pri;
/*! Call to send transfer success/fail response over. */
q931_call *call;
/*! Invocation ID to use when sending a reply to the transfer request. */
int invoke_id;
};
#endif /* defined(HAVE_PRI_TRANSFER) */
#if defined(HAVE_PRI_TRANSFER)
/*!
* \internal
* \brief Send the transfer success/fail response message.
* \since 1.8
*
* \param data Callback user data pointer
* \param is_successful TRUE if the transfer was successful.
*
* \return Nothing
*/
static void sig_pri_transfer_rsp(void *data, int is_successful)
{
struct xfer_rsp_data *rsp = data;
pri_transfer_rsp(rsp->pri->pri, rsp->call, rsp->invoke_id, is_successful);
}
#endif /* defined(HAVE_PRI_TRANSFER) */
#if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
/*!
* \brief Protocol callback to indicate if transfer will happen.
* \since 1.8
*
* \param data Callback user data pointer
* \param is_successful TRUE if the transfer will happen.
*
* \return Nothing
*/
typedef void (*xfer_rsp_callback)(void *data, int is_successful);
#endif /* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
#if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
/*!
* \internal
* \brief Attempt to transfer the two calls to each other.
* \since 1.8
*
* \param pri PRI span control structure.
* \param call_1_pri First call involved in the transfer. (transferee; usually on hold)
* \param call_1_held TRUE if call_1_pri is on hold.
* \param call_2_pri Second call involved in the transfer. (target; usually active/ringing)
* \param call_2_held TRUE if call_2_pri is on hold.
* \param rsp_callback Protocol callback to indicate if transfer will happen. NULL if not used.
* \param data Callback user data pointer
*
* \note Assumes the pri->lock is already obtained.
*
* \retval 0 on success.
* \retval -1 on error.
*/
static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_pri, int call_1_held, q931_call *call_2_pri, int call_2_held, xfer_rsp_callback rsp_callback, void *data)
struct attempt_xfer_call {
q931_call *pri;
struct ast_channel *ast;
int held;
int chanpos;
};
struct ast_channel *transferee;
struct attempt_xfer_call *call_1;
struct attempt_xfer_call *call_2;
struct attempt_xfer_call *swap_call;
struct attempt_xfer_call c1;
struct attempt_xfer_call c2;
c1.pri = call_1_pri;
c1.held = call_1_held;
call_1 = &c1;
c2.pri = call_2_pri;
c2.held = call_2_held;
call_2 = &c2;
Richard Mudgett
committed
call_1->chanpos = pri_find_principle_by_call(pri, call_1->pri);
call_2->chanpos = pri_find_principle_by_call(pri, call_2->pri);
if (call_1->chanpos < 0 || call_2->chanpos < 0) {
/* Calls not found in span control. */
if (rsp_callback) {
/* Transfer failed. */
rsp_callback(data, 0);
}
return -1;
}
/* Attempt to make transferee and target consistent. */
if (!call_1->held && call_2->held) {
/*
* Swap call_1 and call_2 to make call_1 the transferee(held call)
* and call_2 the target(active call).
*/
swap_call = call_1;
call_1 = call_2;
call_2 = swap_call;
}
/* Deadlock avoidance is attempted. */
sig_pri_lock_private(pri->pvts[call_1->chanpos]);
sig_pri_lock_owner(pri, call_1->chanpos);
sig_pri_lock_private(pri->pvts[call_2->chanpos]);
sig_pri_lock_owner(pri, call_2->chanpos);
call_1->ast = pri->pvts[call_1->chanpos]->owner;
call_2->ast = pri->pvts[call_2->chanpos]->owner;
if (!call_1->ast || !call_2->ast) {
/* At least one owner is not present. */
if (call_1->ast) {
ast_channel_unlock(call_1->ast);
}
if (call_2->ast) {
ast_channel_unlock(call_2->ast);
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
if (rsp_callback) {
/* Transfer failed. */
rsp_callback(data, 0);
}
return -1;
}
for (;;) {
transferee = ast_bridged_channel(call_1->ast);
if (transferee) {
break;
}
/* Try masquerading the other way. */
swap_call = call_1;
call_1 = call_2;
call_2 = swap_call;
transferee = ast_bridged_channel(call_1->ast);
if (transferee) {
break;
}
/* Could not transfer. Neither call is bridged. */
ast_channel_unlock(call_1->ast);
ast_channel_unlock(call_2->ast);
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
if (rsp_callback) {
/* Transfer failed. */
rsp_callback(data, 0);
ast_verb(3, "TRANSFERRING %s to %s\n", ast_channel_name(call_1->ast), ast_channel_name(call_2->ast));
/*
* Setup transfer masquerade.
*
* Note: There is an extremely nasty deadlock avoidance issue
* with ast_channel_transfer_masquerade(). Deadlock may be possible if
* the channels involved are proxies (chan_agent channels) and
* it is called with locks. Unfortunately, there is no simple
* or even merely difficult way to guarantee deadlock avoidance
* and still be able to send an ECT success response without the
* possibility of the bridged channel hanging up on us.
*/
ast_mutex_unlock(&pri->lock);
retval = ast_channel_transfer_masquerade(
call_2->ast,
ast_channel_connected(call_2->ast),
call_2->held,
transferee,
ast_channel_connected(call_1->ast),
call_1->held);
/* Reacquire the pri->lock to hold off completion of the transfer masquerade. */
ast_mutex_lock(&pri->lock);
ast_channel_unlock(call_1->ast);
ast_channel_unlock(call_2->ast);
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
if (rsp_callback) {
/*
* Must do the callback before the masquerade completes to ensure
* that the protocol message goes out before the call leg is
* disconnected.
*/
rsp_callback(data, retval ? 0 : 1);
#endif /* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
* \brief Compare the CC agent private data by libpri cc_id.
Kevin P. Fleming
committed
* \since 1.8
* \param obj pointer to the (user-defined part) of an object.
* \param arg callback argument from ao2_callback()
* \param flags flags from ao2_callback()
* \return values are a combination of enum _cb_results.
static int sig_pri_cc_agent_cmp_cc_id(void *obj, void *arg, int flags)
struct ast_cc_agent *agent_1 = obj;
struct sig_pri_cc_agent_prv *agent_prv_1 = agent_1->private_data;
struct sig_pri_cc_agent_prv *agent_prv_2 = arg;
return (agent_prv_1 && agent_prv_1->pri == agent_prv_2->pri
&& agent_prv_1->cc_id == agent_prv_2->cc_id) ? CMP_MATCH | CMP_STOP : 0;
}
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
/*!
* \internal
* \brief Find the CC agent by libpri cc_id.
* \since 1.8
*
* \param pri PRI span control structure.
* \param cc_id CC record ID to find.
*
* \note
* Since agents are refcounted, and this function returns
* a reference to the agent, it is imperative that you decrement
* the refcount of the agent once you have finished using it.
*
* \retval agent on success.
* \retval NULL not found.
*/
static struct ast_cc_agent *sig_pri_find_cc_agent_by_cc_id(struct sig_pri_span *pri, long cc_id)
{
struct sig_pri_cc_agent_prv finder = {
.pri = pri,
.cc_id = cc_id,
};
return ast_cc_agent_callback(0, sig_pri_cc_agent_cmp_cc_id, &finder,
sig_pri_cc_type_name);
}
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
/*!
* \internal
* \brief Compare the CC monitor instance by libpri cc_id.
* \since 1.8
*
* \param obj pointer to the (user-defined part) of an object.
* \param arg callback argument from ao2_callback()
* \param flags flags from ao2_callback()
*
* \return values are a combination of enum _cb_results.
*/
static int sig_pri_cc_monitor_cmp_cc_id(void *obj, void *arg, int flags)
{
struct sig_pri_cc_monitor_instance *monitor_1 = obj;
struct sig_pri_cc_monitor_instance *monitor_2 = arg;
return (monitor_1->pri == monitor_2->pri
&& monitor_1->cc_id == monitor_2->cc_id) ? CMP_MATCH | CMP_STOP : 0;
}
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
/*!
* \internal
* \brief Find the CC monitor instance by libpri cc_id.
* \since 1.8
*
* \param pri PRI span control structure.
* \param cc_id CC record ID to find.
*
* \note
* Since monitor_instances are refcounted, and this function returns
* a reference to the instance, it is imperative that you decrement
* the refcount of the instance once you have finished using it.
*
* \retval monitor_instance on success.
* \retval NULL not found.
*/
static struct sig_pri_cc_monitor_instance *sig_pri_find_cc_monitor_by_cc_id(struct sig_pri_span *pri, long cc_id)
{
struct sig_pri_cc_monitor_instance finder = {
.pri = pri,
.cc_id = cc_id,
};
return ao2_callback(sig_pri_cc_monitors, 0, sig_pri_cc_monitor_cmp_cc_id, &finder);
}
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
/*!
* \internal
* \brief Destroy the given monitor instance.
* \since 1.8
*
* \param data Monitor instance to destroy.
*
* \return Nothing
*/
static void sig_pri_cc_monitor_instance_destroy(void *data)
{
struct sig_pri_cc_monitor_instance *monitor_instance = data;
Richard Mudgett
committed
if (monitor_instance->cc_id != -1) {
ast_mutex_lock(&monitor_instance->pri->lock);
pri_cc_cancel(monitor_instance->pri->pri, monitor_instance->cc_id);
ast_mutex_unlock(&monitor_instance->pri->lock);
}
sig_pri_callbacks.module_unref();
}
#endif /* defined(HAVE_PRI_CCSS) */
Richard Mudgett
committed
#if defined(HAVE_PRI_CCSS)
/*!
* \internal
* \brief Construct a new monitor instance.
* \since 1.8
*
* \param core_id CC core ID.
* \param pri PRI span control structure.
* \param cc_id CC record ID.
* \param device_name Name of device (Asterisk channel name less sequence number).
*
* \note
* Since monitor_instances are refcounted, and this function returns
* a reference to the instance, it is imperative that you decrement
* the refcount of the instance once you have finished using it.
*
* \retval monitor_instance on success.
* \retval NULL on error.
*/
static struct sig_pri_cc_monitor_instance *sig_pri_cc_monitor_instance_init(int core_id, struct sig_pri_span *pri, long cc_id, const char *device_name)
{
struct sig_pri_cc_monitor_instance *monitor_instance;
Richard Mudgett
committed
if (!sig_pri_callbacks.module_ref || !sig_pri_callbacks.module_unref) {
Richard Mudgett
committed
monitor_instance = ao2_alloc(sizeof(*monitor_instance) + strlen(device_name),
sig_pri_cc_monitor_instance_destroy);
if (!monitor_instance) {
return NULL;
}
Richard Mudgett
committed
monitor_instance->cc_id = cc_id;
monitor_instance->pri = pri;
monitor_instance->core_id = core_id;
strcpy(monitor_instance->name, device_name);
Richard Mudgett
committed
sig_pri_callbacks.module_ref();
Richard Mudgett
committed
ao2_link(sig_pri_cc_monitors, monitor_instance);
return monitor_instance;
#endif /* defined(HAVE_PRI_CCSS) */
Richard Mudgett
committed
/*!
* \internal
* \brief Announce to the CC core that protocol CC monitor is available for this call.
Kevin P. Fleming
committed
* \since 1.8
Richard Mudgett
committed
*
* \param pri PRI span control structure.
* \param chanpos Channel position in the span.
* \param cc_id CC record ID.
* \param service CCBS/CCNR indication.
Richard Mudgett
committed
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
* \note Assumes the sig_pri_lock_owner(pri, chanpos) is already obtained.
Richard Mudgett
committed
*
* \retval 0 on success.
* \retval -1 on error.
*/
static int sig_pri_cc_available(struct sig_pri_span *pri, int chanpos, long cc_id, enum ast_cc_service_type service)
Richard Mudgett
committed
{
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
struct sig_pri_chan *pvt;
struct ast_cc_config_params *cc_params;
struct sig_pri_cc_monitor_instance *monitor;
enum ast_cc_monitor_policies monitor_policy;
int core_id;
int res;
char device_name[AST_CHANNEL_NAME];
char dialstring[AST_CHANNEL_NAME];
pvt = pri->pvts[chanpos];
core_id = ast_cc_get_current_core_id(pvt->owner);
if (core_id == -1) {
return -1;
}
cc_params = ast_channel_get_cc_config_params(pvt->owner);
if (!cc_params) {
return -1;
}
res = -1;
monitor_policy = ast_get_cc_monitor_policy(cc_params);
switch (monitor_policy) {
case AST_CC_MONITOR_NEVER:
/* CCSS is not enabled. */
break;
case AST_CC_MONITOR_NATIVE:
case AST_CC_MONITOR_ALWAYS:
/*
* If it is AST_CC_MONITOR_ALWAYS and native fails we will attempt the fallback
* later in the call to sig_pri_cc_generic_check().
*/
ast_channel_get_device_name(pvt->owner, device_name, sizeof(device_name));
sig_pri_make_cc_dialstring(pvt, dialstring, sizeof(dialstring));
monitor = sig_pri_cc_monitor_instance_init(core_id, pri, cc_id, device_name);
if (!monitor) {
break;
}
res = ast_queue_cc_frame(pvt->owner, sig_pri_cc_type_name, dialstring, service,
monitor);
if (res) {
monitor->cc_id = -1;
ao2_unlink(sig_pri_cc_monitors, monitor);
ao2_ref(monitor, -1);
}
break;
case AST_CC_MONITOR_GENERIC:
ast_queue_cc_frame(pvt->owner, AST_CC_GENERIC_MONITOR_TYPE,
sig_pri_get_orig_dialstring(pvt), service, NULL);
/* Say it failed to force caller to cancel native CC. */
break;
}
return res;
}
#endif /* defined(HAVE_PRI_CCSS) */
/*!
* \internal
* \brief Check if generic CC monitor is needed and request it.
* \since 1.8
*
* \param pri PRI span control structure.
* \param chanpos Channel position in the span.
* \param service CCBS/CCNR indication.
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
*
* \return Nothing
*/
static void sig_pri_cc_generic_check(struct sig_pri_span *pri, int chanpos, enum ast_cc_service_type service)
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
{
struct ast_channel *owner;
struct ast_cc_config_params *cc_params;
#if defined(HAVE_PRI_CCSS)
struct ast_cc_monitor *monitor;
char device_name[AST_CHANNEL_NAME];
#endif /* defined(HAVE_PRI_CCSS) */
enum ast_cc_monitor_policies monitor_policy;
int core_id;
if (!pri->pvts[chanpos]->outgoing) {
/* This is not an outgoing call so it cannot be CC monitor. */
return;
}
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (!owner) {
return;
}
core_id = ast_cc_get_current_core_id(owner);
if (core_id == -1) {
/* No CC core setup */
goto done;
}
cc_params = ast_channel_get_cc_config_params(owner);
if (!cc_params) {
/* Could not get CC config parameters. */
goto done;
}
#if defined(HAVE_PRI_CCSS)
ast_channel_get_device_name(owner, device_name, sizeof(device_name));
monitor = ast_cc_get_monitor_by_recall_core_id(core_id, device_name);
if (monitor) {
/* CC monitor is already present so no need for generic CC. */
ao2_ref(monitor, -1);
goto done;
}
#endif /* defined(HAVE_PRI_CCSS) */
monitor_policy = ast_get_cc_monitor_policy(cc_params);
switch (monitor_policy) {
case AST_CC_MONITOR_NEVER:
/* CCSS is not enabled. */
break;
case AST_CC_MONITOR_NATIVE:
if (pri->sig == SIG_BRI_PTMP && pri->nodetype == PRI_NETWORK) {
/* Request generic CC monitor. */
ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
}
break;
case AST_CC_MONITOR_ALWAYS:
if (pri->sig == SIG_BRI_PTMP && pri->nodetype != PRI_NETWORK) {
/*
* Cannot monitor PTMP TE side since this is not defined.
* We are playing the roll of a phone in this case and
* a phone cannot monitor a party over the network without
* protocol help.
*/
break;
}
/*
* We are either falling back or this is a PTMP NT span.
* Request generic CC monitor.
*/
ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
break;
case AST_CC_MONITOR_GENERIC:
if (pri->sig == SIG_BRI_PTMP && pri->nodetype == PRI_NETWORK) {
/* Request generic CC monitor. */
ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
}
break;
}
done:
ast_channel_unlock(owner);
}
#if defined(HAVE_PRI_CCSS)
/*!
* \internal
* \brief The CC link canceled the CC instance.
* \since 1.8
*
* \param pri PRI span control structure.
* \param cc_id CC record ID.
* \param is_agent TRUE if the cc_id is for an agent.
*
* \return Nothing
*/
static void sig_pri_cc_link_canceled(struct sig_pri_span *pri, long cc_id, int is_agent)
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
{
if (is_agent) {
struct ast_cc_agent *agent;
agent = sig_pri_find_cc_agent_by_cc_id(pri, cc_id);
if (!agent) {
return;
}
ast_cc_failed(agent->core_id, "%s agent got canceled by link",
sig_pri_cc_type_name);
ao2_ref(agent, -1);
} else {
struct sig_pri_cc_monitor_instance *monitor;
monitor = sig_pri_find_cc_monitor_by_cc_id(pri, cc_id);
if (!monitor) {
return;
}
monitor->cc_id = -1;
ast_cc_monitor_failed(monitor->core_id, monitor->name,
"%s monitor got canceled by link", sig_pri_cc_type_name);
ao2_ref(monitor, -1);
}
}
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_AOC_EVENTS)
/*!
* \internal
* \brief Convert ast_aoc_charged_item to PRI_AOC_CHARGED_ITEM .
* \since 1.8
*
* \param value Value to convert to string.
*
static enum PRI_AOC_CHARGED_ITEM sig_pri_aoc_charged_item_to_pri(enum PRI_AOC_CHARGED_ITEM value)
switch (value) {
case AST_AOC_CHARGED_ITEM_NA:
return PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
return PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
return PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
return PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT;
case AST_AOC_CHARGED_ITEM_CALL_SETUP:
return PRI_AOC_CHARGED_ITEM_CALL_SETUP;
case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
return PRI_AOC_CHARGED_ITEM_USER_USER_INFO;
case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
return PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
}
return PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
}
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
/*!
* \internal
* \brief Convert PRI_AOC_CHARGED_ITEM to ast_aoc_charged_item.
* \since 1.8
*
* \param value Value to convert to string.
*
* \return ast_aoc_charged_item
*/
static enum ast_aoc_s_charged_item sig_pri_aoc_charged_item_to_ast(enum PRI_AOC_CHARGED_ITEM value)
{
switch (value) {
case PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE:
case PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
return AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
case PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
return AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
case PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT:
case PRI_AOC_CHARGED_ITEM_CALL_SETUP:
case PRI_AOC_CHARGED_ITEM_USER_USER_INFO:
return AST_AOC_CHARGED_ITEM_USER_USER_INFO;
case PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
return AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
}
#endif /* defined(HAVE_PRI_AOC_EVENTS) */