[libpri-commits] rmudgett: branch rmudgett/ect r1498 - /team/rmudgett/ect/
SVN commits to the libpri project
libpri-commits at lists.digium.com
Tue Feb 16 17:48:38 CST 2010
Author: rmudgett
Date: Tue Feb 16 17:48:33 2010
New Revision: 1498
URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1498
Log:
Add code to handle received ETSI ECT requests.
Modified:
team/rmudgett/ect/libpri.h
team/rmudgett/ect/pri.c
team/rmudgett/ect/pri_facility.c
team/rmudgett/ect/pri_internal.h
team/rmudgett/ect/q931.c
Modified: team/rmudgett/ect/libpri.h
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/ect/libpri.h?view=diff&rev=1498&r1=1497&r2=1498
==============================================================================
--- team/rmudgett/ect/libpri.h (original)
+++ team/rmudgett/ect/libpri.h Tue Feb 16 17:48:33 2010
@@ -538,6 +538,7 @@
#define PRI_SUBCMD_CC_CALL 14 /*!< Indicate that this call is a CC callback */
#define PRI_SUBCMD_CC_CANCEL 15 /*!< Unsolicited indication that CC is canceled */
#define PRI_SUBCMD_CC_STOP_ALERTING 16 /*!< Indicate that someone else has responed to remote user free */
+#define PRI_SUBCMD_TRANSFER_CALL 17 /*!< Request to transfer the specified calls together. */
#if defined(STATUS_REQUEST_PLACE_HOLDER)
struct pri_subcmd_status_request {
@@ -632,6 +633,19 @@
* list it should search for the cc_id.
*/
int is_agent;
+};
+
+struct pri_subcmd_transfer {
+ /*! \brief Opaque call pointer for transfer with other call. */
+ q931_call *call_1;
+ /*! \brief Opaque call pointer for transfer with other call. */
+ q931_call *call_2;
+ /*! TRUE if call_1 is on hold. */
+ int is_call_1_held;
+ /*! TRUE if call_2 is on hold. */
+ int is_call_2_held;
+ /*! Invocation ID to use when sending a reply to the transfer request. */
+ int invoke_id;
};
struct pri_subcommand {
@@ -658,6 +672,7 @@
struct pri_subcmd_cc_status cc_status;
struct pri_subcmd_cc_id cc_call;
struct pri_subcmd_cc_cancel cc_cancel;
+ struct pri_subcmd_transfer transfer;
} u;
};
@@ -1330,6 +1345,29 @@
int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code);
/*!
+ * \brief Set the call transfer feature enable flag.
+ *
+ * \param ctrl D channel controller.
+ * \param enable TRUE to enable call transfer feature.
+ *
+ * \return Nothing
+ */
+void pri_transfer_enable(struct pri *ctrl, int enable);
+
+/*!
+ * \brief Send the call transfer response message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param invoke_id Value given by the initiating request.
+ * \param is_successful TRUE if the transfer was successful.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_transfer_rsp(struct pri *ctrl, q931_call *call, int invoke_id, int is_successful);
+
+/*!
* \brief Set the call hold feature enable flag.
*
* \param ctrl D channel controller.
Modified: team/rmudgett/ect/pri.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/ect/pri.c?view=diff&rev=1498&r1=1497&r2=1498
==============================================================================
--- team/rmudgett/ect/pri.c (original)
+++ team/rmudgett/ect/pri.c Tue Feb 16 17:48:33 2010
@@ -1591,6 +1591,14 @@
sr->keypad_digits = keypad_digits;
}
+void pri_transfer_enable(struct pri *ctrl, int enable)
+{
+ ctrl = PRI_MASTER(ctrl);
+ if (ctrl) {
+ ctrl->transfer_support = enable ? 1 : 0;
+ }
+}
+
void pri_hold_enable(struct pri *ctrl, int enable)
{
ctrl = PRI_MASTER(ctrl);
Modified: team/rmudgett/ect/pri_facility.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/ect/pri_facility.c?view=diff&rev=1498&r1=1497&r2=1498
==============================================================================
--- team/rmudgett/ect/pri_facility.c (original)
+++ team/rmudgett/ect/pri_facility.c Tue Feb 16 17:48:33 2010
@@ -2511,6 +2511,196 @@
return 0;
}
+/*!
+ * \internal
+ * \brief Encode ETSI ECT LinkId result respnose 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 invoke_id Invoke id to put in result message.
+ * \param link_id Requested link id to put in result message.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ect_link_id_rsp(struct pri *ctrl, unsigned char *pos,
+ unsigned char *end, int invoke_id, int link_id)
+{
+ struct rose_msg_result msg;
+
+ pos = facility_encode_header(ctrl, pos, end, NULL);
+ if (!pos) {
+ return NULL;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.invoke_id = invoke_id;
+ msg.operation = ROSE_ETSI_EctLinkIdRequest;
+
+ msg.args.etsi.EctLinkIdRequest.link_id = link_id;
+
+ pos = rose_encode_result(ctrl, pos, end, &msg);
+
+ return pos;
+}
+
+/*!
+ * \internal
+ * \brief Send EctLinkIdRequest result response message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param invoke_id Invoke id to put in result message.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_ect_link_id_rsp(struct pri *ctrl, q931_call *call, int invoke_id)
+{
+ unsigned char buffer[256];
+ unsigned char *end;
+
+ end = enc_etsi_ect_link_id_rsp(ctrl, buffer, buffer + sizeof(buffer), invoke_id,
+ call->link_id);
+ if (!end) {
+ return -1;
+ }
+
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+ if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
+ || q931_facility(call->pri, call)) {
+ pri_message(ctrl, "Could not schedule facility message for call %d\n", call->cr);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Process the received ETSI EctExecute message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param invoke_id Invoke id to put in response message.
+ *
+ * \details
+ * 1) Find the active call implied by the transfer request.
+ * 2) Create the PRI_SUBCMD_TRANSFER_CALL event.
+ *
+ * \retval ROSE_ERROR_None on success.
+ * \retval error_code on error.
+ */
+static enum rose_error_code etsi_ect_execute_transfer(struct pri *ctrl, q931_call *call, int invoke_id)
+{
+ enum rose_error_code error_code;
+ struct pri_subcommand *subcmd;
+ q931_call *call_active;
+
+ switch (call->ourcallstate) {
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_CALL_RECEIVED:
+ case Q931_CALL_STATE_CONNECT_REQUEST:
+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_ACTIVE:
+ if (call->master_call->hold_state != Q931_HOLD_STATE_CALL_HELD) {
+ /* EctExecute must be sent on the held call. */
+ error_code = ROSE_ERROR_Gen_InvalidCallState;
+ break;
+ }
+ /* Held call is being transferred. */
+ call_active = q931_find_held_active_call(ctrl, call);
+ if (!call_active) {
+ error_code = ROSE_ERROR_Gen_NotAvailable;
+ break;
+ }
+
+ /* Setup transfer subcommand */
+ subcmd = q931_alloc_subcommand(ctrl);
+ if (!subcmd) {
+ error_code = ROSE_ERROR_Gen_NotAvailable;
+ break;
+ }
+ subcmd->cmd = PRI_SUBCMD_TRANSFER_CALL;
+ subcmd->u.transfer.call_1 = call->master_call;
+ subcmd->u.transfer.call_2 = call_active;
+ subcmd->u.transfer.is_call_1_held = 1;
+ subcmd->u.transfer.is_call_2_held = 0;
+ subcmd->u.transfer.invoke_id = invoke_id;
+
+ error_code = ROSE_ERROR_None;
+ break;
+ default:
+ error_code = ROSE_ERROR_Gen_InvalidCallState;
+ break;
+ }
+
+ return error_code;
+}
+
+/*!
+ * \internal
+ * \brief Process the received ETSI ExplicitEctExecute message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param invoke_id Invoke id to put in response message.
+ * \param link_id Link id of the other call involved in the transfer.
+ *
+ * \details
+ * 1) Find the other call specified by the link_id in transfer request.
+ * 2) Create the PRI_SUBCMD_TRANSFER_CALL event.
+ *
+ * \retval ROSE_ERROR_None on success.
+ * \retval error_code on error.
+ */
+static enum rose_error_code etsi_explicit_ect_execute_transfer(struct pri *ctrl, q931_call *call, int invoke_id, int link_id)
+{
+ enum rose_error_code error_code;
+ struct pri_subcommand *subcmd;
+ q931_call *call_2;
+
+ switch (call->ourcallstate) {
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_CALL_RECEIVED:
+ case Q931_CALL_STATE_CONNECT_REQUEST:
+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_ACTIVE:
+ call_2 = q931_find_link_id_call(ctrl, link_id);
+ if (!call_2 || call_2 == call->master_call) {
+ error_code = ROSE_ERROR_Gen_NotAvailable;
+ break;
+ }
+
+ /* Setup transfer subcommand */
+ subcmd = q931_alloc_subcommand(ctrl);
+ if (!subcmd) {
+ error_code = ROSE_ERROR_Gen_NotAvailable;
+ break;
+ }
+ subcmd->cmd = PRI_SUBCMD_TRANSFER_CALL;
+ subcmd->u.transfer.call_1 = call->master_call;
+ subcmd->u.transfer.call_2 = call_2;
+ subcmd->u.transfer.is_call_1_held =
+ (call->master_call->hold_state == Q931_HOLD_STATE_CALL_HELD) ? 1 : 0;
+ subcmd->u.transfer.is_call_2_held =
+ (call_2->hold_state == Q931_HOLD_STATE_CALL_HELD) ? 1 : 0;
+ subcmd->u.transfer.invoke_id = invoke_id;
+
+ error_code = ROSE_ERROR_None;
+ break;
+ default:
+ error_code = ROSE_ERROR_Gen_InvalidCallState;
+ break;
+ }
+
+ return error_code;
+}
+
/* AOC */
/*!
* \internal
@@ -3413,6 +3603,19 @@
break;
}
return send_facility_error(ctrl, call, invoke_id, rose_err);
+}
+
+int pri_transfer_rsp(struct pri *ctrl, q931_call *call, int invoke_id, int is_successful)
+{
+ if (!ctrl || !call) {
+ return -1;
+ }
+
+ if (is_successful) {
+ return rose_result_ok_encode(ctrl, call, Q931_DISCONNECT, invoke_id);
+ } else {
+ return send_facility_error(ctrl, call, invoke_id, ROSE_ERROR_Gen_NotAvailable);
+ }
}
/*!
@@ -3666,6 +3869,7 @@
struct q931_party_id party_id;
struct q931_party_address party_address;
struct q931_party_redirecting deflection;
+ enum rose_error_code error_code;
switch (invoke->operation) {
#if 0 /* Not handled yet */
@@ -3965,21 +4169,50 @@
case ROSE_ITU_IdentificationOfCharge:
break;
#endif /* Not handled yet */
-#if 0 /* Not handled yet */
case ROSE_ETSI_EctExecute:
+ if (!PRI_MASTER(ctrl)->transfer_support) {
+ send_facility_error(ctrl, call, invoke->invoke_id,
+ ROSE_ERROR_Gen_NotSubscribed);
+ break;
+ }
+ error_code = etsi_ect_execute_transfer(ctrl, call, invoke->invoke_id);
+ if (error_code != ROSE_ERROR_None) {
+ send_facility_error(ctrl, call, invoke->invoke_id, error_code);
+ } else {
+ send_facility_result_ok(ctrl, call, invoke->invoke_id);
+ }
break;
case ROSE_ETSI_ExplicitEctExecute:
- break;
-#endif /* Not handled yet */
+ error_code = etsi_explicit_ect_execute_transfer(ctrl, call, invoke->invoke_id,
+ invoke->args.etsi.ExplicitEctExecute.link_id);
+ if (error_code != ROSE_ERROR_None) {
+ send_facility_error(ctrl, call, invoke->invoke_id, error_code);
+ } else {
+ send_facility_result_ok(ctrl, call, invoke->invoke_id);
+ }
+ break;
case ROSE_ETSI_RequestSubaddress:
/* Ignore since we are not handling subaddresses yet. */
break;
#if 0 /* Not handled yet */
case ROSE_ETSI_SubaddressTransfer:
break;
+#endif /* Not handled yet */
case ROSE_ETSI_EctLinkIdRequest:
- break;
-#endif /* Not handled yet */
+ if (!PRI_MASTER(ctrl)->transfer_support) {
+ send_facility_error(ctrl, call, invoke->invoke_id,
+ ROSE_ERROR_Gen_ResourceUnavailable);
+ break;
+ }
+ /*
+ * Use the invoke_id sequence number as a link_id.
+ * It should be safe enough to do this. If not then we will have to search
+ * the call pool to ensure that the link_id is not already in use.
+ */
+ call->master_call->link_id = get_invokeid(ctrl);
+ call->master_call->is_link_id_valid = 1;
+ send_ect_link_id_rsp(ctrl, call, invoke->invoke_id);
+ break;
case ROSE_ETSI_EctInform:
/* redirectionNumber is put in remote_id.number */
if (invoke->args.etsi.EctInform.redirection_present) {
@@ -3993,10 +4226,13 @@
call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
}
break;
-#if 0 /* Not handled yet */
case ROSE_ETSI_EctLoopTest:
- break;
-#endif /* Not handled yet */
+ /*
+ * The ETS 300 369 specification does a very poor job describing
+ * how this message is used to detect loops.
+ */
+ send_facility_error(ctrl, call, invoke->invoke_id, ROSE_ERROR_Gen_NotAvailable);
+ break;
#if defined(STATUS_REQUEST_PLACE_HOLDER)
case ROSE_ETSI_StatusRequest:
/* Not handled yet */
Modified: team/rmudgett/ect/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/ect/pri_internal.h?view=diff&rev=1498&r1=1497&r2=1498
==============================================================================
--- team/rmudgett/ect/pri_internal.h (original)
+++ team/rmudgett/ect/pri_internal.h Tue Feb 16 17:48:33 2010
@@ -98,9 +98,11 @@
int protodisc;
unsigned int bri:1;
unsigned int acceptinbanddisconnect:1; /* Should we allow inband progress after DISCONNECT? */
+ unsigned int sendfacility:1;
unsigned int hold_support:1;/* TRUE if upper layer supports call hold. */
unsigned int deflection_support:1;/* TRUE if upper layer supports call deflection/rerouting. */
unsigned int cc_support:1;/* TRUE if upper layer supports call completion. */
+ unsigned int transfer_support:1;/* TRUE if the upper layer supports ECT */
/* MDL variables */
int mdl_error;
@@ -173,7 +175,6 @@
#endif
short last_invoke; /* Last ROSE invoke ID (Valid in master record only) */
- unsigned char sendfacility;
/*! Call completion (Valid in master record only) */
struct {
@@ -582,6 +583,11 @@
int transferable; /* RLT call is transferable */
unsigned int rlt_call_id; /* RLT call id */
+
+ /*! ETSI Explicit Call Transfer link id. */
+ int link_id;
+ /*! TRUE if link_id is valid. */
+ int is_link_id_valid;
/* Bridged call info */
q931_call *bridged_call; /* Pointer to other leg of bridged call (Used by Q.SIG when eliminating tromboned calls) */
@@ -940,6 +946,9 @@
int q931_master_pass_event(struct pri *ctrl, struct q931_call *subcall, int msg_type);
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_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);
Modified: team/rmudgett/ect/q931.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/ect/q931.c?view=diff&rev=1498&r1=1497&r2=1498
==============================================================================
--- team/rmudgett/ect/q931.c (original)
+++ team/rmudgett/ect/q931.c Tue Feb 16 17:48:33 2010
@@ -6886,7 +6886,53 @@
}
/*!
- * \internal
+ * \brief Find the transfer call indicated by the given link_id.
+ *
+ * \param ctrl D channel controller.
+ * \param link_id Link id of the other call involved in the transfer.
+ *
+ * \retval found-master-call on success.
+ * \retval NULL on error.
+ */
+struct q931_call *q931_find_link_id_call(struct pri *ctrl, int link_id)
+{
+ struct pri *master;
+ struct q931_call *cur;
+ struct q931_call *winner;
+ struct q931_call *match;
+
+ match = NULL;
+ master = PRI_MASTER(ctrl);
+ for (cur = *master->callpool; cur; cur = cur->next) {
+ if (cur->is_link_id_valid && cur->link_id == link_id) {
+ /* Found the link_id call. */
+ winner = q931_find_winning_call(cur);
+ if (!winner) {
+ /* There is no winner. */
+ break;
+ }
+ switch (winner->ourcallstate) {
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_CALL_RECEIVED:
+ case Q931_CALL_STATE_CONNECT_REQUEST:
+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_ACTIVE:
+ /* The link_id call is in a state suitable for transfer. */
+ match = cur;
+ break;
+ default:
+ /* The link_id call is not in a good state to transfer. */
+ break;
+ }
+ break;
+ }
+ }
+
+ return match;
+}
+
+/*!
* \brief Find the active call given the held call.
*
* \param ctrl D channel controller.
@@ -6895,7 +6941,7 @@
* \retval master-active-call on success.
* \retval NULL on error.
*/
-static struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call)
+struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call)
{
struct pri *master;
struct q931_call *cur;
More information about the libpri-commits
mailing list