[libpri-commits] rmudgett: branch group/ccss r1372 - /team/group/ccss/
SVN commits to the libpri project
libpri-commits at lists.digium.com
Tue Dec 8 21:06:56 CST 2009
Author: rmudgett
Date: Tue Dec 8 21:06:52 2009
New Revision: 1372
URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1372
Log:
PTMP agent FSM written. Needs testing.
* Added call-completion FSM support infrastructure.
* Added PRI_DEBUG_CC output enable flag.
* Added conversion routines to/from rose and q931 party address
structures.
* Added Q931_ANY_MESSAGE with support so facility messages can go out on
any Q.931 message going out next.
* Fixed handling of ROSE APDU response messages coming in on broadcast
and specific dummy call reference call.
* Fixed handling of ROSE APDU response message timeout to allow the
callback to be able to delete the apdu_event structure safely.
Modified:
team/group/ccss/libpri.h
team/group/ccss/pri_cc.c
team/group/ccss/pri_facility.c
team/group/ccss/pri_facility.h
team/group/ccss/pri_internal.h
team/group/ccss/pri_q931.h
team/group/ccss/q931.c
Modified: team/group/ccss/libpri.h
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/libpri.h?view=diff&rev=1372&r1=1371&r2=1372
==============================================================================
--- team/group/ccss/libpri.h (original)
+++ team/group/ccss/libpri.h Tue Dec 8 21:06:52 2009
@@ -51,6 +51,7 @@
#define PRI_DEBUG_Q931_ANOMALY (1 << 7) /* Show unexpected events */
#define PRI_DEBUG_APDU (1 << 8) /* Debug of APDU components such as ROSE */
#define PRI_DEBUG_AOC (1 << 9) /* Debug of Advice of Charge ROSE Messages */
+#define PRI_DEBUG_CC (1 << 10) /* Debug call-completion. */
#define PRI_DEBUG_ALL (0xffff) /* Everything */
@@ -1454,7 +1455,7 @@
long pri_cc_available(struct pri *ctrl, q931_call *call);
int pri_cc_req(struct pri *ctrl, long cc_id, int mode);
void pri_cc_req_rsp(struct pri *ctrl, long cc_id, int status);
-void pri_cc_remote_user_free(struct pri *ctrl, long cc_id);
+int pri_cc_remote_user_free(struct pri *ctrl, long cc_id, int is_ccbs_busy);
int pri_cc_status_req(struct pri *ctrl, long cc_id);
void pri_cc_status_req_rsp(struct pri *ctrl, long cc_id, int status);
void pri_cc_status(struct pri *ctrl, long cc_id, int status);
Modified: team/group/ccss/pri_cc.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_cc.c?view=diff&rev=1372&r1=1371&r2=1372
==============================================================================
--- team/group/ccss/pri_cc.c (original)
+++ team/group/ccss/pri_cc.c Tue Dec 8 21:06:52 2009
@@ -344,13 +344,13 @@
* \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.
+ * \param cc_record Call completion record to process event.
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
static unsigned char *enc_etsi_ptmp_cc_available(struct pri *ctrl, unsigned char *pos,
- unsigned char *end, q931_call *call)
+ unsigned char *end, struct pri_cc_record *cc_record)
{
struct rose_msg_invoke msg;
@@ -363,7 +363,7 @@
msg.invoke_id = get_invokeid(ctrl);
msg.operation = ROSE_ETSI_CallInfoRetain;
- msg.args.etsi.CallInfoRetain.call_linkage_id = call->cc.record->call_linkage_id;
+ msg.args.etsi.CallInfoRetain.call_linkage_id = cc_record->call_linkage_id;
pos = rose_encode_invoke(ctrl, pos, end, &msg);
@@ -371,16 +371,18 @@
}
/*!
+ * \internal
* \brief Encode and queue a cc-available message.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param call Call leg from which to encode call completion available.
+ * \param cc_record Call completion record to process event.
* \param msgtype Q.931 message type to put facility ie in.
*
* \retval 0 on success.
* \retval -1 on error.
*/
-int rose_cc_available_encode(struct pri *ctrl, q931_call *call, int msgtype)
+static int rose_cc_available_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int msgtype)
{
unsigned char buffer[256];
unsigned char *end;
@@ -390,7 +392,8 @@
case PRI_SWITCH_EUROISDN_T1:
if (q931_is_ptmp(ctrl)) {
end =
- enc_etsi_ptmp_cc_available(ctrl, buffer, buffer + sizeof(buffer), call);
+ enc_etsi_ptmp_cc_available(ctrl, buffer, buffer + sizeof(buffer),
+ cc_record);
} else {
end =
enc_etsi_ptp_cc_operation(ctrl, buffer, buffer + sizeof(buffer),
@@ -411,69 +414,2105 @@
}
/*!
- * \brief Send an event from the upper layer to the cc state machine.
+ * \internal
+ * \brief Encode ETSI PTMP EraseCallLinkageID 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 cc_record Call completion record to process event.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ptmp_erase_call_linkage(struct pri *ctrl,
+ unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
+{
+ struct rose_msg_invoke msg;
+
+ pos = facility_encode_header(ctrl, pos, end, NULL);
+ if (!pos) {
+ return NULL;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.invoke_id = get_invokeid(ctrl);
+ msg.operation = ROSE_ETSI_EraseCallLinkageID;
+
+ msg.args.etsi.EraseCallLinkageID.call_linkage_id = cc_record->call_linkage_id;
+
+ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+ return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode and queue an EraseCallLinkageID message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode EraseCallLinkageID.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_erase_call_linkage_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ unsigned char buffer[256];
+ unsigned char *end;
+
+ end =
+ enc_etsi_ptmp_erase_call_linkage(ctrl, buffer, buffer + sizeof(buffer),
+ cc_record);
+ if (!end) {
+ return -1;
+ }
+
+ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+}
+
+/*!
+ * \internal
+ * \brief Encode and send an EraseCallLinkageID message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode EraseCallLinkageID.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_erase_call_linkage_id(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ if (rose_erase_call_linkage_encode(ctrl, call, cc_record)
+ || q931_facility(ctrl, call)) {
+ pri_message(ctrl,
+ "Could not schedule facility message for EraseCallLinkageID.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Encode ETSI PTMP CCBSErase 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 cc_record Call completion record to process event.
+ * \param reason CCBS Erase reason
+ * normal-unspecified(0), t-CCBS2-timeout(1), t-CCBS3-timeout(2), basic-call-failed(3)
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ptmp_ccbs_erase(struct pri *ctrl,
+ unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record, int reason)
+{
+ struct rose_msg_invoke msg;
+
+ pos = facility_encode_header(ctrl, pos, end, NULL);
+ if (!pos) {
+ return NULL;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.invoke_id = get_invokeid(ctrl);
+ msg.operation = ROSE_ETSI_CCBSErase;
+
+/* BUGBUG need BC, HLC, and LLC from initial SETUP */
+ //msg.args.etsi.CCBSErase.q931ie.contents
+ //msg.args.etsi.CCBSErase.q931ie.length = ;
+
+ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CCBSErase.address_of_b,
+ &cc_record->party_b);
+ msg.args.etsi.CCBSErase.recall_mode = cc_record->option.recall_mode;
+ msg.args.etsi.CCBSErase.ccbs_reference = cc_record->ccbs_reference_id;
+ msg.args.etsi.CCBSErase.reason = reason;
+
+ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+ return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode and queue an CCBSErase message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode CCBSErase.
+ * \param cc_record Call completion record to process event.
+ * \param reason CCBS Erase reason
+ * normal-unspecified(0), t-CCBS2-timeout(1), t-CCBS3-timeout(2), basic-call-failed(3)
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_ccbs_erase_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int reason)
+{
+ unsigned char buffer[256];
+ unsigned char *end;
+
+ end =
+ enc_etsi_ptmp_ccbs_erase(ctrl, buffer, buffer + sizeof(buffer), cc_record,
+ reason);
+ if (!end) {
+ return -1;
+ }
+
+ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+}
+
+/*!
+ * \internal
+ * \brief Encode and send an CCBSErase message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode EraseCallLinkageID.
+ * \param cc_record Call completion record to process event.
+ * \param reason CCBS Erase reason
+ * normal-unspecified(0), t-CCBS2-timeout(1), t-CCBS3-timeout(2), basic-call-failed(3)
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_ccbs_erase(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int reason)
+{
+ if (rose_ccbs_erase_encode(ctrl, call, cc_record, reason)
+ || q931_facility(ctrl, call)) {
+ pri_message(ctrl,
+ "Could not schedule facility message for CCBSErase.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Encode ETSI PTMP CCBSStatusRequest 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 cc_record Call completion record to process event.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ptmp_ccbs_status_request(struct pri *ctrl,
+ unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
+{
+ struct rose_msg_invoke msg;
+
+ pos = facility_encode_header(ctrl, pos, end, NULL);
+ if (!pos) {
+ return NULL;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.invoke_id = get_invokeid(ctrl);
+ msg.operation = ROSE_ETSI_CCBSStatusRequest;
+
+/* BUGBUG need BC, HLC, and LLC from initial SETUP */
+ //msg.args.etsi.CCBSStatusRequest.q931ie.contents
+ //msg.args.etsi.CCBSStatusRequest.q931ie.length = ;
+
+ msg.args.etsi.CCBSStatusRequest.recall_mode = cc_record->option.recall_mode;
+ msg.args.etsi.CCBSStatusRequest.ccbs_reference = cc_record->ccbs_reference_id;
+
+ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+ return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode ETSI PTMP CCBSBFree 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 cc_record Call completion record to process event.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ptmp_ccbs_b_free(struct pri *ctrl,
+ unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
+{
+ struct rose_msg_invoke msg;
+
+ pos = facility_encode_header(ctrl, pos, end, NULL);
+ if (!pos) {
+ return NULL;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.invoke_id = get_invokeid(ctrl);
+ msg.operation = ROSE_ETSI_CCBSBFree;
+
+/* BUGBUG need BC, HLC, and LLC from initial SETUP */
+ //msg.args.etsi.CCBSBFree.q931ie.contents
+ //msg.args.etsi.CCBSBFree.q931ie.length = ;
+
+ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CCBSBFree.address_of_b,
+ &cc_record->party_b);
+ msg.args.etsi.CCBSBFree.recall_mode = cc_record->option.recall_mode;
+ msg.args.etsi.CCBSBFree.ccbs_reference = cc_record->ccbs_reference_id;
+
+ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+ return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode and queue an CCBSBFree message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode CCBSBFree.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_ccbs_b_free_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ unsigned char buffer[256];
+ unsigned char *end;
+
+ end =
+ enc_etsi_ptmp_ccbs_b_free(ctrl, buffer, buffer + sizeof(buffer), cc_record);
+ if (!end) {
+ return -1;
+ }
+
+ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+}
+
+/*!
+ * \internal
+ * \brief Encode and send an CCBSBFree message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode CCBSBFree.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_ccbs_b_free(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ if (rose_ccbs_b_free_encode(ctrl, call, cc_record)
+ || q931_facility(ctrl, call)) {
+ pri_message(ctrl,
+ "Could not schedule facility message for CCBSBFree.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Encode ETSI PTMP CCBSRemoteUserFree 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 cc_record Call completion record to process event.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ptmp_remote_user_free(struct pri *ctrl,
+ unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
+{
+ struct rose_msg_invoke msg;
+
+ pos = facility_encode_header(ctrl, pos, end, NULL);
+ if (!pos) {
+ return NULL;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.invoke_id = get_invokeid(ctrl);
+ msg.operation = ROSE_ETSI_CCBSRemoteUserFree;
+
+/* BUGBUG need BC, HLC, and LLC from initial SETUP */
+ //msg.args.etsi.CCBSRemoteUserFree.q931ie.contents
+ //msg.args.etsi.CCBSRemoteUserFree.q931ie.length = ;
+
+ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CCBSRemoteUserFree.address_of_b,
+ &cc_record->party_b);
+ msg.args.etsi.CCBSRemoteUserFree.recall_mode = cc_record->option.recall_mode;
+ msg.args.etsi.CCBSRemoteUserFree.ccbs_reference = cc_record->ccbs_reference_id;
+
+ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+ return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode and queue a remote user free message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode remote user free message.
+ * \param cc_record Call completion record to process event.
+ * \param msgtype Q.931 message type to put facility ie in.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_remote_user_free_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int msgtype)
+{
+ unsigned char buffer[256];
+ unsigned char *end;
+
+ switch (ctrl->switchtype) {
+ case PRI_SWITCH_EUROISDN_E1:
+ case PRI_SWITCH_EUROISDN_T1:
+ if (q931_is_ptmp(ctrl)) {
+ end =
+ enc_etsi_ptmp_remote_user_free(ctrl, buffer, buffer + sizeof(buffer),
+ cc_record);
+ } else {
+ end =
+ enc_etsi_ptp_cc_operation(ctrl, buffer, buffer + sizeof(buffer),
+ ROSE_ETSI_CCBS_T_RemoteUserFree);
+ }
+ break;
+ case PRI_SWITCH_QSIG:
+ /* BUGBUG rose_remote_user_free_encode(Q.SIG) not written. */
+ return -1;
+ default:
+ return -1;
+ }
+ if (!end) {
+ return -1;
+ }
+
+ return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
+}
+
+/*!
+ * \internal
+ * \brief Encode and send an remote user free message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode remote user free.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_remote_user_free(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ if (rose_remote_user_free_encode(ctrl, call, cc_record, Q931_FACILITY)
+ || q931_facility(ctrl, call)) {
+ pri_message(ctrl,
+ "Could not schedule facility message for remote user free.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Encode ETSI PTMP CCBSStopAlerting 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 cc_record Call completion record to process event.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ptmp_ccbs_stop_alerting(struct pri *ctrl,
+ unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
+{
+ struct rose_msg_invoke msg;
+
+ pos = facility_encode_header(ctrl, pos, end, NULL);
+ if (!pos) {
+ return NULL;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.invoke_id = get_invokeid(ctrl);
+ msg.operation = ROSE_ETSI_CCBSStopAlerting;
+
+ msg.args.etsi.CCBSStopAlerting.ccbs_reference = cc_record->ccbs_reference_id;
+
+ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+ return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode and queue an CCBSStopAlerting message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode CCBSStopAlerting.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_ccbs_stop_alerting_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ unsigned char buffer[256];
+ unsigned char *end;
+
+ end =
+ enc_etsi_ptmp_ccbs_stop_alerting(ctrl, buffer, buffer + sizeof(buffer), cc_record);
+ if (!end) {
+ return -1;
+ }
+
+ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+}
+
+/*!
+ * \internal
+ * \brief Encode and send CCBSStopAlerting message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode remote user free.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_ccbs_stop_alerting(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ if (rose_ccbs_stop_alerting_encode(ctrl, call, cc_record)
+ || q931_facility(ctrl, call)) {
+ pri_message(ctrl,
+ "Could not schedule facility message for CCBSStopAlerting.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Convert the given call completion state to a string.
+ *
+ * \param state CC state to convert to string.
+ *
+ * \return String version of call completion state.
+ */
+static const char *pri_cc_fsm_state_str(enum CC_STATES state)
+{
+ const char *str;
+
+ str = "Unknown";
+ switch (state) {
+ case CC_STATE_IDLE:
+ str = "CC_STATE_IDLE";
+ break;
+ case CC_STATE_PENDING_AVAILABLE:
+ str = "CC_STATE_PENDING_AVAILABLE";
+ break;
+ case CC_STATE_AVAILABLE:
+ str = "CC_STATE_AVAILABLE";
+ break;
+ case CC_STATE_REQUESTED:
+ str = "CC_STATE_REQUESTED";
+ break;
+ case CC_STATE_ACTIVATED:
+ str = "CC_STATE_ACTIVATED";
+ break;
+ case CC_STATE_B_AVAILABLE:
+ str = "CC_STATE_B_AVAILABLE";
+ break;
+ case CC_STATE_SUSPENDED:
+ str = "CC_STATE_SUSPENDED";
+ break;
+ case CC_STATE_WAIT_CALLBACK:
+ str = "CC_STATE_WAIT_CALLBACK";
+ break;
+ case CC_STATE_CALLBACK:
+ str = "CC_STATE_CALLBACK";
+ break;
+ case CC_STATE_WAIT_DESTRUCTION:
+ str = "CC_STATE_WAIT_DESTRUCTION";
+ break;
+ case CC_STATE_NUM:
+ /* Not a real state. */
+ break;
+ }
+ return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the given call completion event to a string.
+ *
+ * \param event CC event to convert to string.
+ *
+ * \return String version of call completion event.
+ */
+static const char *pri_cc_fsm_event_str(enum CC_EVENTS event)
+{
+ const char *str;
+
+ str = "Unknown";
+ switch (event) {
+ case CC_EVENT_AVAILABLE:
+ str = "CC_EVENT_AVAILABLE";
+ break;
+ case CC_EVENT_CC_REQUEST:
+ str = "CC_EVENT_CC_REQUEST";
+ break;
+ case CC_EVENT_CC_REQUEST_ACCEPT:
+ str = "CC_EVENT_CC_REQUEST_ACCEPT";
+ break;
+ case CC_EVENT_REMOTE_USER_FREE:
+ str = "CC_EVENT_REMOTE_USER_FREE";
+ break;
+ case CC_EVENT_A_STATUS:
+ str = "CC_EVENT_A_STATUS";
+ break;
+ case CC_EVENT_A_FREE:
+ str = "CC_EVENT_A_FREE";
+ break;
+ case CC_EVENT_A_BUSY:
+ str = "CC_EVENT_A_BUSY";
+ break;
+ case CC_EVENT_SUSPEND:
+ str = "CC_EVENT_SUSPEND";
+ break;
+ case CC_EVENT_RESUME:
+ str = "CC_EVENT_RESUME";
+ break;
+ case CC_EVENT_RECALL:
+ str = "CC_EVENT_RECALL";
+ break;
+ case CC_EVENT_LINK_CANCEL:
+ str = "CC_EVENT_LINK_CANCEL";
+ break;
+ case CC_EVENT_CANCEL:
+ str = "CC_EVENT_CANCEL";
+ break;
+ case CC_EVENT_SIGNALING_GONE:
+ str = "CC_EVENT_SIGNALING_GONE";
+ break;
+ case CC_EVENT_MSG_ALERTING:
+ str = "CC_EVENT_MSG_ALERTING";
+ break;
+ case CC_EVENT_MSG_DISCONNECT:
+ str = "CC_EVENT_MSG_DISCONNECT";
+ break;
+ case CC_EVENT_MSG_RELEASE:
+ str = "CC_EVENT_MSG_RELEASE";
+ break;
+ case CC_EVENT_MSG_RELEASE_COMPLETE:
+ str = "CC_EVENT_MSG_RELEASE_COMPLETE";
+ break;
+ case CC_EVENT_TIMEOUT_T_RETENTION:
+ str = "CC_EVENT_TIMEOUT_T_RETENTION";
+ break;
+ case CC_EVENT_TIMEOUT_T_CCBS1:
+ str = "CC_EVENT_TIMEOUT_T_CCBS1";
+ break;
+ case CC_EVENT_TIMEOUT_EXTENDED_T_CCBS1:
+ str = "CC_EVENT_TIMEOUT_EXTENDED_T_CCBS1";
+ break;
+ case CC_EVENT_TIMEOUT_T_CCBS2:
+ str = "CC_EVENT_TIMEOUT_T_CCBS2";
+ break;
+ case CC_EVENT_TIMEOUT_T_CCBS3:
+ str = "CC_EVENT_TIMEOUT_T_CCBS3";
+ break;
+ }
+ return str;
+}
+
+static const char pri_cc_act_header[] = " CC-Act: %s\n";
+#define PRI_CC_ACT_DEBUG_OUTPUT(ctrl) \
+ if ((ctrl)->debug & PRI_DEBUG_CC) { \
+ pri_message((ctrl), pri_cc_act_header, __FUNCTION__); \
+ }
+
+/*!
+ * \internal
+ * \brief FSM action to mark FSM for destruction.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_set_self_destruct(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ cc_record->fsm_complete = 1;
+}
+
+/*!
+ * \internal
+ * \brief FSM action to send CC available message.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg.
* \param cc_record Call completion record to process event.
+ * \param msgtype Q.931 message type to put facility ie in.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_send_cc_available(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int msgtype)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ rose_cc_available_encode(ctrl, call, cc_record, msgtype);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to stop the PTMP T_RETENTION timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_stop_t_retention(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ pri_schedule_del(ctrl, cc_record->fsm.ptmp.t_retention);
+ cc_record->fsm.ptmp.t_retention = 0;
+}
+
+/*!
+ * \internal
+ * \brief T_RETENTION timeout callback.
+ *
+ * \param data CC record pointer.
+ *
+ * \return Nothing
+ */
+static void pri_cc_timeout_t_retention(void *data)
+{
+ struct pri_cc_record *cc_record = data;
+
+ cc_record->fsm.ptmp.t_retention = 0;
+ q931_cc_timeout(cc_record->signaling->pri, cc_record->signaling, cc_record,
+ CC_EVENT_TIMEOUT_T_RETENTION);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to start the PTMP T_RETENTION timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_start_t_retention(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ if (cc_record->fsm.ptmp.t_retention) {
+ pri_error(ctrl, "!! T_RETENTION is already running!");
+ pri_schedule_del(ctrl, cc_record->fsm.ptmp.t_retention);
+ }
+ cc_record->fsm.ptmp.t_retention = pri_schedule_event(ctrl,
+ ctrl->timers[PRI_TIMER_T_RETENTION], pri_cc_timeout_t_retention, cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to stop the PTMP EXTENDED_T_CCBS1 timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_stop_extended_t_ccbs1(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ pri_schedule_del(ctrl, cc_record->fsm.ptmp.extended_t_ccbs1);
+ cc_record->fsm.ptmp.extended_t_ccbs1 = 0;
+}
+
+/*!
+ * \internal
+ * \brief EXTENDED_T_CCBS1 timeout callback.
+ *
+ * \param data CC record pointer.
+ *
+ * \return Nothing
+ */
+static void pri_cc_timeout_extended_t_ccbs1(void *data)
+{
+ struct pri_cc_record *cc_record = data;
+
+ cc_record->fsm.ptmp.extended_t_ccbs1 = 0;
+ q931_cc_timeout(cc_record->signaling->pri, cc_record->signaling, cc_record,
+ CC_EVENT_TIMEOUT_EXTENDED_T_CCBS1);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to start the PTMP extended T_CCBS1 timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_start_extended_t_ccbs1(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ if (cc_record->fsm.ptmp.extended_t_ccbs1) {
+ pri_error(ctrl, "!! Extended T_CCBS1 is already running!");
+ pri_schedule_del(ctrl, cc_record->fsm.ptmp.extended_t_ccbs1);
+ }
+ /* Timeout is T_CCBS1 + 2 seconds. */
+ cc_record->fsm.ptmp.extended_t_ccbs1 = pri_schedule_event(ctrl,
+ ctrl->timers[PRI_TIMER_T_CCBS1] + 2000, pri_cc_timeout_extended_t_ccbs1,
+ cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to stop the PTMP T_CCBS2 timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_stop_t_ccbs2(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ pri_schedule_del(ctrl, cc_record->fsm.ptmp.t_ccbs2);
+ cc_record->fsm.ptmp.t_ccbs2 = 0;
+}
+
+/*!
+ * \internal
+ * \brief T_CCBS2 timeout callback.
+ *
+ * \param data CC record pointer.
+ *
+ * \return Nothing
+ */
+static void pri_cc_timeout_t_ccbs2(void *data)
+{
+ struct pri_cc_record *cc_record = data;
+
+ cc_record->fsm.ptmp.t_ccbs2 = 0;
+ q931_cc_timeout(cc_record->signaling->pri, cc_record->signaling, cc_record,
+ CC_EVENT_TIMEOUT_T_CCBS2);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to start the PTMP T_CCBS2 timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_start_t_ccbs2(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ if (cc_record->fsm.ptmp.t_ccbs2) {
+ pri_error(ctrl, "!! T_CCBS2/T_CCNR2 is already running!");
+ pri_schedule_del(ctrl, cc_record->fsm.ptmp.t_ccbs2);
+ }
+ cc_record->fsm.ptmp.t_ccbs2 = pri_schedule_event(ctrl,
+ ctrl->timers[cc_record->is_ccnr ? PRI_TIMER_T_CCNR2 : PRI_TIMER_T_CCBS2],
+ pri_cc_timeout_t_ccbs2, cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to stop the PTMP T_CCBS3 timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_stop_t_ccbs3(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ pri_schedule_del(ctrl, cc_record->fsm.ptmp.t_ccbs3);
+ cc_record->fsm.ptmp.t_ccbs3 = 0;
+}
+
+/*!
+ * \internal
+ * \brief T_CCBS3 timeout callback.
+ *
+ * \param data CC record pointer.
+ *
+ * \return Nothing
+ */
+static void pri_cc_timeout_t_ccbs3(void *data)
+{
+ struct pri_cc_record *cc_record = data;
+
+ cc_record->fsm.ptmp.t_ccbs3 = 0;
+ q931_cc_timeout(cc_record->signaling->pri, cc_record->signaling, cc_record,
+ CC_EVENT_TIMEOUT_T_CCBS3);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to start the PTMP T_CCBS3 timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_start_t_ccbs3(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ if (cc_record->fsm.ptmp.t_ccbs3) {
+ pri_error(ctrl, "!! T_CCBS3 is already running!");
+ pri_schedule_del(ctrl, cc_record->fsm.ptmp.t_ccbs3);
+ }
+ cc_record->fsm.ptmp.t_ccbs3 = pri_schedule_event(ctrl,
+ ctrl->timers[PRI_TIMER_T_CCBS3], pri_cc_timeout_t_ccbs3, cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to send the EraseCallLinkageID message.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_send_erase_call_linkage_id(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ send_erase_call_linkage_id(ctrl, cc_record->signaling, cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to send the CCBSErase message.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ * \param reason CCBS Erase reason
+ * normal-unspecified(0), t-CCBS2-timeout(1), t-CCBS3-timeout(2), basic-call-failed(3)
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_send_ccbs_erase(struct pri *ctrl, struct pri_cc_record *cc_record, int reason)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ send_ccbs_erase(ctrl, cc_record->signaling, cc_record, reason);
+}
+
+/*!
+ * \internal
+ * \brief Find the T_CCBS1 timer/CCBSStatusRequest message.
+ *
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Facility message pointer or NULL if not active.
+ */
+static struct apdu_event *pri_cc_get_t_ccbs1_status(struct pri_cc_record *cc_record)
+{
+ return pri_call_apdu_find(cc_record->signaling,
+ cc_record->fsm.ptmp.t_ccbs1_invoke_id);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to stop the PTMP T_CCBS1 timer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_stop_t_ccbs1(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ struct apdu_event *msg;
+
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+
+ msg = pri_cc_get_t_ccbs1_status(cc_record);
+ if (msg) {
+ pri_call_apdu_delete(cc_record->signaling, msg);
+ }
+}
+
+/*!
+ * \internal
+ * \brief CCBSStatusRequest response callback function.
+ *
+ * \param reason Reason callback is called.
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param apdu APDU queued entry. Do not change!
+ * \param msg APDU response message data. (NULL if was not the reason called.)
+ *
+ * \return TRUE if no more responses are expected.
+ */
+static int pri_cc_ccbs_status_response(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const union apdu_msg_data *msg)
+{
+ struct pri_cc_record *cc_record;
+
+ cc_record = apdu->response.user.ptr;
+ switch (reason) {
+ case APDU_CALLBACK_REASON_TIMEOUT:
+ pri_cc_event(ctrl, call, cc_record, CC_EVENT_TIMEOUT_T_CCBS1);
+ break;
+ case APDU_CALLBACK_REASON_MSG_RESULT:
+ pri_cc_event(ctrl, call, cc_record, msg->result->args.etsi.CCBSStatusRequest.free
+ ? CC_EVENT_A_FREE : CC_EVENT_A_BUSY);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Encode and queue an CCBSStatusRequest message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode CCBSStatusRequest.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_ccbs_status_request(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ unsigned char buffer[256];
+ unsigned char *end;
+ struct apdu_callback_data response;
+
+ end =
+ enc_etsi_ptmp_ccbs_status_request(ctrl, buffer, buffer + sizeof(buffer),
+ cc_record);
+ if (!end) {
+ return -1;
+ }
+
+ memset(&response, 0, sizeof(response));
+ response.invoke_id = ctrl->last_invoke;
+ response.timeout_time = ctrl->timers[PRI_TIMER_T_CCBS1];
+ response.callback = pri_cc_ccbs_status_response;
+ response.user.ptr = cc_record;
+ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, &response);
+}
+
+/*!
+ * \internal
+ * \brief Encode and send an CCBSStatusRequest message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode CCBSStatusRequest.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_ccbs_status_request(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ if (rose_ccbs_status_request(ctrl, call, cc_record)
+ || q931_facility(ctrl, call)) {
+ pri_message(ctrl,
+ "Could not schedule facility message for CCBSStatusRequest.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief FSM action to send the CCBSStatusRequest message.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_send_ccbs_status_request(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ send_ccbs_status_request(ctrl, cc_record->signaling, cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to send the CCBSBFree message.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_send_ccbs_b_free(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ send_ccbs_b_free(ctrl, cc_record->signaling, cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to send the remote user free message.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_send_remote_user_free(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ send_remote_user_free(ctrl, cc_record->signaling, cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to send the CCBSStopAlerting message.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_send_ccbs_stop_alerting(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ send_ccbs_stop_alerting(ctrl, cc_record->signaling, cc_record);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to release the call linkage id.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_release_link_id(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ cc_record->call_linkage_id = CC_PTMP_INVALID_ID;
+}
+
+/*!
+ * \internal
+ * \brief FSM action to reset raw A status.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_reset_raw_a_status(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ cc_record->fsm.ptmp.party_a_status_acc = CC_PARTY_A_AVAILABILITY_INVALID;
+}
+
+/*!
+ * \internal
+ * \brief FSM action to add raw A status with busy.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_add_raw_a_status_busy(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ if (cc_record->fsm.ptmp.party_a_status_acc != CC_PARTY_A_AVAILABILITY_FREE) {
+ cc_record->fsm.ptmp.party_a_status_acc = CC_PARTY_A_AVAILABILITY_BUSY;
+ }
+}
+
+/*!
+ * \internal
+ * \brief FSM action to set raw A status to free.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_set_raw_a_status_free(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ cc_record->fsm.ptmp.party_a_status_acc = CC_PARTY_A_AVAILABILITY_FREE;
+}
+
+/*!
+ * \internal
+ * \brief Fill in the status response party A status update event.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fill_status_rsp_a(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+ struct pri_subcommand *subcmd;
+
+ if (cc_record->fsm.ptmp.party_a_status_acc == CC_PARTY_A_AVAILABILITY_INVALID) {
+ /* Accumulated party A status is invalid so don't pass it up. */
+ return;
+ }
+
+ subcmd = q931_alloc_subcommand(ctrl);
+ if (!subcmd) {
+ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
+ return;
+ }
+
+ subcmd->cmd = PRI_SUBCMD_CC_STATUS_REQ_RSP;
+ subcmd->u.cc_status_req_rsp.cc_id = cc_record->record_id;
+ subcmd->u.cc_status_req_rsp.status =
+ (cc_record->fsm.ptmp.party_a_status_acc == CC_PARTY_A_AVAILABILITY_FREE)
+ ? 0 /* free */ : 1 /* busy */;
+}
+
+/*!
+ * \internal
+ * \brief Pass up party A status to upper layer (indirectly).
+ *
+ * \param data CC record pointer.
+ *
+ * \return Nothing
+ */
+static void pri_cc_indirect_status_rsp_a(void *data)
+{
+ struct pri_cc_record *cc_record = data;
+
+ q931_cc_indirect(cc_record->signaling->pri, cc_record->signaling, cc_record,
+ pri_cc_fill_status_rsp_a);
+}
+
+/*!
+ * \internal
+ * \brief FSM action to pass up party A status to upper layer (indirectly).
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ *
+ * \note
+ * Warning: Must not use this action with pri_cc_act_set_self_destruct() in the
+ * same event.
+ */
+static void pri_cc_act_pass_up_status_rsp_a_indirect(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+ PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+ if (cc_record->fsm.ptmp.party_a_status_acc != CC_PARTY_A_AVAILABILITY_INVALID) {
+ /* Accumulated party A status is not invalid so pass it up. */
+ pri_schedule_event(ctrl, 0, pri_cc_indirect_status_rsp_a, cc_record);
+ }
+}
+
+/*!
+ * \internal
+ * \brief FSM action to pass up party A status to upper layer.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_pass_up_status_rsp_a(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
[... 2195 lines stripped ...]
More information about the libpri-commits
mailing list