Add call transfer exchange of subaddresses support and fix PTMP call transfer signaling.
* Add the ability to exchange subaddresses for ETSI PTMP, ETSI PTP, and Q.SIG for call transfer. * Fix ETSI PTMP to send the correct messages depending on the call state for call transfer. NOTE: Some ISDN phones only handle the NOTIFY message that the EN 300-369 spec says should be sent only if the call has not connected yet. JIRA LIBPRI-47 JIRA SWP-2363 Review: https://reviewboard.asterisk.org/r/1051/ git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@2172 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
4faa2935f8
commit
19e2a84c89
111
pri.c
111
pri.c
@ -949,6 +949,9 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr
|
||||
{
|
||||
struct q931_party_id party_id;
|
||||
unsigned idx;
|
||||
unsigned new_name;
|
||||
unsigned new_number;
|
||||
unsigned new_subaddress;
|
||||
struct q931_call *subcall;
|
||||
|
||||
if (!ctrl || !pri_is_call_valid(ctrl, call)) {
|
||||
@ -957,13 +960,14 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr
|
||||
|
||||
pri_copy_party_id_to_q931(&party_id, &connected->id);
|
||||
q931_party_id_fixup(ctrl, &party_id);
|
||||
if (!q931_party_id_cmp(&party_id, &call->local_id)) {
|
||||
/* The local party information did not change so do nothing. */
|
||||
return 0;
|
||||
}
|
||||
call->local_id = party_id;
|
||||
|
||||
/* Update all subcalls with new local_id. */
|
||||
new_name = q931_party_name_cmp(&party_id.name, &call->local_id.name);
|
||||
new_number = q931_party_number_cmp(&party_id.number, &call->local_id.number);
|
||||
new_subaddress = party_id.subaddress.valid
|
||||
&& q931_party_subaddress_cmp(&party_id.subaddress, &call->local_id.subaddress);
|
||||
|
||||
/* Update the call and all subcalls with new local_id. */
|
||||
call->local_id = party_id;
|
||||
if (call->outboundbroadcast && call->master_call == call) {
|
||||
for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) {
|
||||
subcall = call->subcalls[idx];
|
||||
@ -982,23 +986,100 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr
|
||||
* The local party transferred to someone else before
|
||||
* the remote end answered.
|
||||
*/
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_EUROISDN_E1:
|
||||
case PRI_SWITCH_EUROISDN_T1:
|
||||
if (BRI_NT_PTMP(ctrl)) {
|
||||
/*
|
||||
* NT PTMP mode
|
||||
*
|
||||
* We should not send these messages to the network if we are
|
||||
* the CPE side since phones do not transfer calls within
|
||||
* themselves. Well... If you consider handing the handset to
|
||||
* someone else a transfer then how is the network to know?
|
||||
*/
|
||||
if (new_number) {
|
||||
q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
|
||||
&party_id.number);
|
||||
}
|
||||
if (new_subaddress || (party_id.subaddress.valid && new_number)) {
|
||||
q931_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
} else if (PTP_MODE(ctrl)) {
|
||||
/* PTP mode */
|
||||
if (new_number) {
|
||||
/* Immediately send EctInform APDU, callStatus=answered(0) */
|
||||
send_call_transfer_complete(ctrl, call, 0);
|
||||
}
|
||||
if (new_subaddress || (party_id.subaddress.valid && new_number)) {
|
||||
q931_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PRI_SWITCH_QSIG:
|
||||
if (new_name || new_number) {
|
||||
/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
|
||||
send_call_transfer_complete(ctrl, call, 0);
|
||||
}
|
||||
if (new_subaddress
|
||||
|| (party_id.subaddress.valid && (new_name || new_number))) {
|
||||
q931_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Q931_CALL_STATE_ACTIVE:
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_EUROISDN_E1:
|
||||
case PRI_SWITCH_EUROISDN_T1:
|
||||
if (PTMP_MODE(ctrl)) {
|
||||
/* PTMP mode */
|
||||
q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
|
||||
&call->local_id.number);
|
||||
} else {
|
||||
if (BRI_NT_PTMP(ctrl)) {
|
||||
/*
|
||||
* NT PTMP mode
|
||||
*
|
||||
* We should not send these messages to the network if we are
|
||||
* the CPE side since phones do not transfer calls within
|
||||
* themselves. Well... If you consider handing the handset to
|
||||
* someone else a transfer then how is the network to know?
|
||||
*/
|
||||
if (new_number) {
|
||||
#if defined(USE_NOTIFY_FOR_ECT)
|
||||
/*
|
||||
* Some ISDN phones only handle the NOTIFY message that the
|
||||
* EN 300-369 spec says should be sent only if the call has not
|
||||
* connected yet.
|
||||
*/
|
||||
q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
|
||||
&party_id.number);
|
||||
#else
|
||||
q931_request_subaddress(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
|
||||
&party_id.number);
|
||||
#endif /* defined(USE_NOTIFY_FOR_ECT) */
|
||||
}
|
||||
if (new_subaddress || (party_id.subaddress.valid && new_number)) {
|
||||
q931_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
} else if (PTP_MODE(ctrl)) {
|
||||
/* PTP mode */
|
||||
/* Immediately send EctInform APDU, callStatus=answered(0) */
|
||||
send_call_transfer_complete(ctrl, call, 0);
|
||||
if (new_number) {
|
||||
/* Immediately send EctInform APDU, callStatus=answered(0) */
|
||||
send_call_transfer_complete(ctrl, call, 0);
|
||||
}
|
||||
if (new_subaddress || (party_id.subaddress.valid && new_number)) {
|
||||
q931_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PRI_SWITCH_QSIG:
|
||||
/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
|
||||
send_call_transfer_complete(ctrl, call, 0);
|
||||
if (new_name || new_number) {
|
||||
/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
|
||||
send_call_transfer_complete(ctrl, call, 0);
|
||||
}
|
||||
if (new_subaddress
|
||||
|| (party_id.subaddress.valid && (new_name || new_number))) {
|
||||
q931_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
313
pri_facility.c
313
pri_facility.c
@ -3365,6 +3365,286 @@ int send_call_transfer_complete(struct pri *ctrl, q931_call *call, int call_stat
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Encode the ETSI RequestSubaddress invoke message.
|
||||
*
|
||||
* \param ctrl D channel controller for diagnostic messages or global options.
|
||||
* \param pos Starting position to encode the facility ie contents.
|
||||
* \param end End of facility ie contents encoding data buffer.
|
||||
*
|
||||
* \retval Start of the next ASN.1 component to encode on success.
|
||||
* \retval NULL on error.
|
||||
*/
|
||||
static unsigned char *enc_etsi_request_subaddress(struct pri *ctrl, unsigned char *pos,
|
||||
unsigned char *end)
|
||||
{
|
||||
struct rose_msg_invoke msg;
|
||||
|
||||
pos = facility_encode_header(ctrl, pos, end, NULL);
|
||||
if (!pos) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.operation = ROSE_ETSI_RequestSubaddress;
|
||||
msg.invoke_id = get_invokeid(ctrl);
|
||||
|
||||
pos = rose_encode_invoke(ctrl, pos, end, &msg);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Encode and queue the RequestSubaddress invoke message.
|
||||
*
|
||||
* \param ctrl D channel controller for diagnostic messages or global options.
|
||||
* \param call Call leg from which to encode message.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int rose_request_subaddress_encode(struct pri *ctrl, struct q931_call *call)
|
||||
{
|
||||
unsigned char buffer[256];
|
||||
unsigned char *end;
|
||||
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_EUROISDN_E1:
|
||||
case PRI_SWITCH_EUROISDN_T1:
|
||||
end = enc_etsi_request_subaddress(ctrl, buffer, buffer + sizeof(buffer));
|
||||
break;
|
||||
case PRI_SWITCH_QSIG:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (!end) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Encode the ETSI SubaddressTransfer invoke message.
|
||||
*
|
||||
* \param ctrl D channel controller for diagnostic messages or global options.
|
||||
* \param pos Starting position to encode the facility ie contents.
|
||||
* \param end End of facility ie contents encoding data buffer.
|
||||
* \param call Call leg from which to encode message.
|
||||
*
|
||||
* \retval Start of the next ASN.1 component to encode on success.
|
||||
* \retval NULL on error.
|
||||
*/
|
||||
static unsigned char *enc_etsi_subaddress_transfer(struct pri *ctrl, unsigned char *pos,
|
||||
unsigned char *end, struct q931_call *call)
|
||||
{
|
||||
struct rose_msg_invoke msg;
|
||||
|
||||
pos = facility_encode_header(ctrl, pos, end, NULL);
|
||||
if (!pos) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.operation = ROSE_ETSI_SubaddressTransfer;
|
||||
msg.invoke_id = get_invokeid(ctrl);
|
||||
|
||||
if (!call->local_id.subaddress.valid) {
|
||||
return NULL;
|
||||
}
|
||||
q931_copy_subaddress_to_rose(ctrl, &msg.args.etsi.SubaddressTransfer.subaddress,
|
||||
&call->local_id.subaddress);
|
||||
|
||||
pos = rose_encode_invoke(ctrl, pos, end, &msg);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Encode the Q.SIG SubaddressTransfer invoke message.
|
||||
*
|
||||
* \param ctrl D channel controller for diagnostic messages or global options.
|
||||
* \param pos Starting position to encode the facility ie contents.
|
||||
* \param end End of facility ie contents encoding data buffer.
|
||||
* \param call Call leg from which to encode message.
|
||||
*
|
||||
* \retval Start of the next ASN.1 component to encode on success.
|
||||
* \retval NULL on error.
|
||||
*/
|
||||
static unsigned char *enc_qsig_subaddress_transfer(struct pri *ctrl,
|
||||
unsigned char *pos, unsigned char *end, struct q931_call *call)
|
||||
{
|
||||
struct fac_extension_header header;
|
||||
struct rose_msg_invoke msg;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.nfe_present = 1;
|
||||
header.nfe.source_entity = 0; /* endPINX */
|
||||
header.nfe.destination_entity = 0; /* endPINX */
|
||||
header.interpretation_present = 1;
|
||||
header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
|
||||
pos = facility_encode_header(ctrl, pos, end, &header);
|
||||
if (!pos) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.operation = ROSE_QSIG_SubaddressTransfer;
|
||||
msg.invoke_id = get_invokeid(ctrl);
|
||||
|
||||
if (!call->local_id.subaddress.valid) {
|
||||
return NULL;
|
||||
}
|
||||
q931_copy_subaddress_to_rose(ctrl,
|
||||
&msg.args.qsig.SubaddressTransfer.redirection_subaddress,
|
||||
&call->local_id.subaddress);
|
||||
|
||||
pos = rose_encode_invoke(ctrl, pos, end, &msg);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Encode and queue the SubaddressTransfer invoke message.
|
||||
*
|
||||
* \param ctrl D channel controller for diagnostic messages or global options.
|
||||
* \param call Call leg from which to encode message.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
static int rose_subaddress_transfer_encode(struct pri *ctrl, struct q931_call *call)
|
||||
{
|
||||
unsigned char buffer[256];
|
||||
unsigned char *end;
|
||||
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_EUROISDN_E1:
|
||||
case PRI_SWITCH_EUROISDN_T1:
|
||||
end =
|
||||
enc_etsi_subaddress_transfer(ctrl, buffer, buffer + sizeof(buffer), call);
|
||||
break;
|
||||
case PRI_SWITCH_QSIG:
|
||||
end =
|
||||
enc_qsig_subaddress_transfer(ctrl, buffer, buffer + sizeof(buffer), call);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (!end) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Send a FACILITY SubaddressTransfer.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param call Q.931 call leg
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int send_subaddress_transfer(struct pri *ctrl, struct q931_call *call)
|
||||
{
|
||||
if (rose_subaddress_transfer_encode(ctrl, call)
|
||||
|| q931_facility(ctrl, call)) {
|
||||
pri_message(ctrl,
|
||||
"Could not schedule facility message for subaddress transfer.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Handle the received RequestSubaddress facility.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param call Q.931 call leg
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void etsi_request_subaddress(struct pri *ctrl, struct q931_call *call)
|
||||
{
|
||||
int changed = 0;
|
||||
|
||||
switch (call->notify) {
|
||||
case PRI_NOTIFY_TRANSFER_ACTIVE:
|
||||
if (q931_party_number_cmp(&call->remote_id.number, &call->redirection_number)) {
|
||||
/* The remote party number information changed. */
|
||||
call->remote_id.number = call->redirection_number;
|
||||
changed = 1;
|
||||
}
|
||||
/* Fall through */
|
||||
case PRI_NOTIFY_TRANSFER_ALERTING:
|
||||
if (call->redirection_number.valid
|
||||
&& q931_party_number_cmp(&call->remote_id.number, &call->redirection_number)) {
|
||||
/* The remote party number information changed. */
|
||||
call->remote_id.number = call->redirection_number;
|
||||
changed = 1;
|
||||
}
|
||||
if (call->remote_id.subaddress.valid) {
|
||||
/*
|
||||
* Clear the subaddress as the remote party has been changed.
|
||||
* Any new subaddress will arrive later.
|
||||
*/
|
||||
q931_party_subaddress_init(&call->remote_id.subaddress);
|
||||
changed = 1;
|
||||
}
|
||||
if (changed) {
|
||||
call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send our subaddress back if we have one. */
|
||||
if (call->local_id.subaddress.valid) {
|
||||
send_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Handle the received SubaddressTransfer facility subaddress.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param call Q.931 call leg
|
||||
* \param subaddr Received subaddress of remote party.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void handle_subaddress_transfer(struct pri *ctrl, struct q931_call *call, const struct rosePartySubaddress *subaddr)
|
||||
{
|
||||
int changed = 0;
|
||||
struct q931_party_subaddress q931_subaddress;
|
||||
|
||||
q931_party_subaddress_init(&q931_subaddress);
|
||||
rose_copy_subaddress_to_q931(ctrl, &q931_subaddress, subaddr);
|
||||
if (q931_party_subaddress_cmp(&call->remote_id.subaddress, &q931_subaddress)) {
|
||||
call->remote_id.subaddress = q931_subaddress;
|
||||
changed = 1;
|
||||
}
|
||||
if (call->redirection_number.valid
|
||||
&& q931_party_number_cmp(&call->remote_id.number, &call->redirection_number)) {
|
||||
/* The remote party number information changed. */
|
||||
call->remote_id.number = call->redirection_number;
|
||||
changed = 1;
|
||||
}
|
||||
if (changed) {
|
||||
call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Encode a plain facility ETSI error code.
|
||||
@ -4382,12 +4662,12 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie
|
||||
}
|
||||
break;
|
||||
case ROSE_ETSI_RequestSubaddress:
|
||||
/* Ignore since we are not handling subaddresses yet. */
|
||||
etsi_request_subaddress(ctrl, call);
|
||||
break;
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_ETSI_SubaddressTransfer:
|
||||
handle_subaddress_transfer(ctrl, call,
|
||||
&invoke->args.etsi.SubaddressTransfer.subaddress);
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
case ROSE_ETSI_EctLinkIdRequest:
|
||||
if (!ctrl->transfer_support) {
|
||||
send_facility_error(ctrl, call, invoke->invoke_id,
|
||||
@ -4409,12 +4689,24 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie
|
||||
rose_copy_presented_number_unscreened_to_q931(ctrl,
|
||||
&call->remote_id.number, &invoke->args.etsi.EctInform.redirection);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the subaddress as the remote party has been changed.
|
||||
* Any new subaddress will arrive later.
|
||||
*/
|
||||
q931_party_subaddress_init(&call->remote_id.subaddress);
|
||||
|
||||
if (!invoke->args.etsi.EctInform.status) {
|
||||
/* The remote party for the transfer has not answered yet. */
|
||||
call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE;
|
||||
} else {
|
||||
call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
|
||||
}
|
||||
|
||||
/* Send our subaddress back if we have one. */
|
||||
if (call->local_id.subaddress.valid) {
|
||||
send_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
break;
|
||||
case ROSE_ETSI_EctLoopTest:
|
||||
/*
|
||||
@ -4826,12 +5118,23 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie
|
||||
&invoke->args.qsig.CallTransferComplete.redirection_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the subaddress as the remote party has been changed.
|
||||
* Any new subaddress will arrive later.
|
||||
*/
|
||||
q931_party_subaddress_init(&call->remote_id.subaddress);
|
||||
|
||||
if (invoke->args.qsig.CallTransferComplete.call_status == 1) {
|
||||
/* The remote party for the transfer has not answered yet. */
|
||||
call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE;
|
||||
} else {
|
||||
call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
|
||||
}
|
||||
|
||||
/* Send our subaddress back if we have one. */
|
||||
if (call->local_id.subaddress.valid) {
|
||||
send_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
break;
|
||||
case ROSE_QSIG_CallTransferUpdate:
|
||||
party_id = call->remote_id;
|
||||
@ -4858,10 +5161,10 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie
|
||||
}
|
||||
}
|
||||
break;
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_QSIG_SubaddressTransfer:
|
||||
handle_subaddress_transfer(ctrl, call,
|
||||
&invoke->args.qsig.SubaddressTransfer.redirection_subaddress);
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
case ROSE_QSIG_PathReplacement:
|
||||
anfpr_pathreplacement_respond(ctrl, call, ie);
|
||||
break;
|
||||
|
@ -221,6 +221,8 @@ int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const
|
||||
int send_reroute_request(struct pri *ctrl, q931_call *call, const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, int subscription_option);
|
||||
|
||||
int send_call_transfer_complete(struct pri *pri, q931_call *call, int call_status);
|
||||
int rose_request_subaddress_encode(struct pri *ctrl, struct q931_call *call);
|
||||
int send_subaddress_transfer(struct pri *ctrl, struct q931_call *call);
|
||||
|
||||
int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call);
|
||||
int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype);
|
||||
|
@ -950,6 +950,8 @@ struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl);
|
||||
struct q931_call *q931_find_link_id_call(struct pri *ctrl, int link_id);
|
||||
struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call);
|
||||
|
||||
int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_number *number);
|
||||
int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call);
|
||||
int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
|
||||
|
||||
struct pri_cc_record *pri_cc_find_by_reference(struct pri *ctrl, unsigned reference_id);
|
||||
|
159
q931.c
159
q931.c
@ -935,6 +935,31 @@ int q931_party_id_presentation(const struct q931_party_id *id)
|
||||
return number_value | number_screening;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
|
||||
*
|
||||
* \param call Starting Q.931 call record of search.
|
||||
*
|
||||
* \retval winning-call or given call if not outboundbroadcast.
|
||||
* \retval NULL if no winning call yet.
|
||||
*/
|
||||
struct q931_call *q931_find_winning_call(struct q931_call *call)
|
||||
{
|
||||
struct q931_call *master;
|
||||
|
||||
master = call->master_call;
|
||||
if (master->outboundbroadcast) {
|
||||
/* We have potential subcalls. Now get the winning call if declared yet. */
|
||||
if (master->pri_winner < 0) {
|
||||
/* Winner not declared yet.*/
|
||||
call = NULL;
|
||||
} else {
|
||||
call = master->subcalls[master->pri_winner];
|
||||
}
|
||||
}
|
||||
return call;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Append the given ie contents to the save ie location.
|
||||
@ -4733,6 +4758,88 @@ int q931_facility(struct pri*ctrl, q931_call *c)
|
||||
return send_message(ctrl, c, Q931_FACILITY, facility_ies);
|
||||
}
|
||||
|
||||
static int facility_notify_ies[] = {
|
||||
Q931_IE_FACILITY,
|
||||
Q931_IE_NOTIFY_IND,
|
||||
Q931_IE_REDIRECTION_NUMBER,
|
||||
-1
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Send a FACILITY RequestSubaddress with optional redirection number.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param call Q.931 call leg
|
||||
* \param notify Notification indicator
|
||||
* \param number Redirection number to send if not NULL.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_number *number)
|
||||
{
|
||||
struct q931_call *winner;
|
||||
|
||||
winner = q931_find_winning_call(call);
|
||||
if (!winner) {
|
||||
return -1;
|
||||
}
|
||||
if (number) {
|
||||
winner->redirection_number = *number;
|
||||
} else {
|
||||
q931_party_number_init(&winner->redirection_number);
|
||||
}
|
||||
winner->notify = notify;
|
||||
if (rose_request_subaddress_encode(ctrl, winner)
|
||||
|| send_message(ctrl, winner, Q931_FACILITY, facility_notify_ies)) {
|
||||
pri_message(ctrl,
|
||||
"Could not schedule facility message for request subaddress.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Send a FACILITY SubaddressTransfer to all parties.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param call Q.931 call leg
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call)
|
||||
{
|
||||
int status;
|
||||
unsigned idx;
|
||||
struct q931_call *subcall;
|
||||
|
||||
if (call->outboundbroadcast && call->master_call == call) {
|
||||
status = 0;
|
||||
for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) {
|
||||
subcall = call->subcalls[idx];
|
||||
if (subcall) {
|
||||
/* Send to all subcalls that have given a positive response. */
|
||||
switch (subcall->ourcallstate) {
|
||||
case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
|
||||
case Q931_CALL_STATE_CALL_DELIVERED:
|
||||
case Q931_CALL_STATE_ACTIVE:
|
||||
if (send_subaddress_transfer(ctrl, subcall)) {
|
||||
status = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = send_subaddress_transfer(ctrl, call);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int notify_ies[] = { Q931_IE_NOTIFY_IND, Q931_IE_REDIRECTION_NUMBER, -1 };
|
||||
|
||||
/*!
|
||||
@ -5493,31 +5600,6 @@ static int q931_release_complete(struct pri *ctrl, q931_call *c, int cause)
|
||||
return res;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
|
||||
*
|
||||
* \param call Starting Q.931 call record of search.
|
||||
*
|
||||
* \retval winning-call or given call if not outboundbroadcast.
|
||||
* \retval NULL if no winning call yet.
|
||||
*/
|
||||
struct q931_call *q931_find_winning_call(struct q931_call *call)
|
||||
{
|
||||
struct q931_call *master;
|
||||
|
||||
master = call->master_call;
|
||||
if (master->outboundbroadcast) {
|
||||
/* We have potential subcalls. Now get the winning call if declared yet. */
|
||||
if (master->pri_winner < 0) {
|
||||
/* Winner not declared yet.*/
|
||||
call = NULL;
|
||||
} else {
|
||||
call = master->subcalls[master->pri_winner];
|
||||
}
|
||||
}
|
||||
return call;
|
||||
}
|
||||
|
||||
static int connect_ack_ies[] = { -1 };
|
||||
static int connect_ack_w_chan_id_ies[] = { Q931_CHANNEL_IDENT, -1 };
|
||||
static int gr303_connect_ack_ies[] = { Q931_CHANNEL_IDENT, -1 };
|
||||
@ -6312,6 +6394,8 @@ static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_ca
|
||||
c->ri = -1;
|
||||
break;
|
||||
case Q931_FACILITY:
|
||||
c->notify = -1;
|
||||
q931_party_number_init(&c->redirection_number);
|
||||
if (q931_is_dummy_call(c)) {
|
||||
q931_party_address_init(&c->called);
|
||||
}
|
||||
@ -6412,6 +6496,7 @@ static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_ca
|
||||
case Q931_SETUP_ACKNOWLEDGE:
|
||||
break;
|
||||
case Q931_NOTIFY:
|
||||
c->notify = -1;
|
||||
q931_party_number_init(&c->redirection_number);
|
||||
break;
|
||||
case Q931_HOLD:
|
||||
@ -7551,6 +7636,7 @@ static struct q931_call *q931_find_held_call(struct pri *ctrl, struct q931_call
|
||||
static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand)
|
||||
{
|
||||
int res;
|
||||
int changed;
|
||||
struct apdu_event *cur = NULL;
|
||||
struct pri_subcommand *subcmd;
|
||||
struct q931_call *master_call;
|
||||
@ -8127,6 +8213,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case Q931_NOTIFY:
|
||||
res = 0;
|
||||
changed = 0;
|
||||
switch (c->notify) {
|
||||
case PRI_NOTIFY_CALL_DIVERTING:
|
||||
if (c->redirection_number.valid) {
|
||||
@ -8159,13 +8246,29 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
res = Q931_RES_HAVEEVENT;
|
||||
}
|
||||
break;
|
||||
case PRI_NOTIFY_TRANSFER_ALERTING:
|
||||
case PRI_NOTIFY_TRANSFER_ACTIVE:
|
||||
if (q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) {
|
||||
/* The remote party number information changed. */
|
||||
c->remote_id.number = c->redirection_number;
|
||||
changed = 1;
|
||||
}
|
||||
/* Fall through */
|
||||
case PRI_NOTIFY_TRANSFER_ALERTING:
|
||||
if (c->redirection_number.valid
|
||||
&& q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) {
|
||||
/* The remote party information changed. */
|
||||
/* The remote party number information changed. */
|
||||
c->remote_id.number = c->redirection_number;
|
||||
|
||||
changed = 1;
|
||||
}
|
||||
if (c->remote_id.subaddress.valid) {
|
||||
/*
|
||||
* Clear the subaddress as the remote party has been changed.
|
||||
* Any new subaddress will arrive later.
|
||||
*/
|
||||
q931_party_subaddress_init(&c->remote_id.subaddress);
|
||||
changed = 1;
|
||||
}
|
||||
if (changed) {
|
||||
/* Setup connected line subcommand */
|
||||
subcmd = q931_alloc_subcommand(ctrl);
|
||||
if (subcmd) {
|
||||
|
Loading…
Reference in New Issue
Block a user