[libpri-commits] rmudgett: branch group/ccss r1385 - /team/group/ccss/

SVN commits to the libpri project libpri-commits at lists.digium.com
Sat Dec 12 02:30:26 CST 2009


Author: rmudgett
Date: Sat Dec 12 02:30:21 2009
New Revision: 1385

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1385
Log:
Commit checkpoint for work in progress.

*  Removed pri_cc_deactivate_req()/PRI_SUBCMD_CC_DEACTIVATE_RSP from
public API.
*  Added PRI_SUBCMD_CC_STOP_ALERTING to public API.
*  Added code to pass the reamaining PTMP CC invoke messages to the PTMP
monitor FSM.  (Remains to be written.)
*  Other tweaks/fixes to PTMP agent FSM and actions.
*  Collected/moved all of the "ERROR: Too many facility subcommands"
messages into q931_alloc_subcommand().

Modified:
    team/group/ccss/libpri.h
    team/group/ccss/pri.c
    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/q931.c

Modified: team/group/ccss/libpri.h
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/libpri.h?view=diff&rev=1385&r1=1384&r2=1385
==============================================================================
--- team/group/ccss/libpri.h (original)
+++ team/group/ccss/libpri.h Sat Dec 12 02:30:21 2009
@@ -527,7 +527,7 @@
 #define PRI_SUBCMD_CC_STATUS				12	/*!< Unsolicited update of CC party A status */
 #define PRI_SUBCMD_CC_CALL					13	/*!< Indicate that this call is a CC callback */
 #define PRI_SUBCMD_CC_CANCEL				14	/*!< Unsolicited indication that CC is canceled */
-#define PRI_SUBCMD_CC_DEACTIVATE_RSP		15	/*!< CC deactivation request response */
+#define PRI_SUBCMD_CC_STOP_ALERTING			15	/*!< Indicate that someone else has responed to remote user free */
 
 struct pri_subcmd_status_request {
 	/*!
@@ -584,18 +584,18 @@
 	 * \details
 	 * success(0),
 	 * timeout(1),
-	 * short_term_denial(2),
-	 * long_term_denial(3),
-	 * not_subscribed(4)
+	 * error(2),
+	 * reject(3)
 	 */
 	int status;
 	/*!
-	 * \brief Error code that can be converted to a string to further
+	 * \brief Failure code that can be converted to a string to further
 	 * explain the non-timeout failure.
-	 * \note Valid when non-zero.
+	 * \note Valid when status is error or reject.
 	 * \note Use pri_facility_error2str() to convert the error_code.
-	 */
-	int error_code;
+	 * \note Use pri_facility_reject2str() to convert the reject_code.
+	 */
+	int fail_code;
 	/*!
 	 * \brief TRUE if negotiated to retain CC service if B busy again.
 	 */
@@ -622,26 +622,6 @@
 	 * busy(1)
 	 */
 	int status;
-};
-
-struct pri_subcmd_cc_deactivate_rsp {
-	/*! \brief Call-Completion record id */
-	long cc_id;
-	/*!
-	 * \brief Status of the requested call-completion deactivation.
-	 * \details
-	 * success(0),
-	 * timeout(1),
-	 * fail(2)
-	 */
-	int status;
-	/*!
-	 * \brief Error code that can be converted to a string to further
-	 * explain the non-timeout failure.
-	 * \note Valid when non-zero.
-	 * \note Use pri_facility_error2str() to convert the error_code.
-	 */
-	int error_code;
 };
 
 struct pri_subcommand {
@@ -664,7 +644,7 @@
 		struct pri_subcmd_cc_status cc_status;
 		struct pri_subcmd_cc_id cc_call;
 		struct pri_subcmd_cc_id cc_cancel;
-		struct pri_subcmd_cc_deactivate_rsp cc_deactivate_rsp;
+		struct pri_subcmd_cc_id cc_stop_alerting;
 	} u;
 };
 
@@ -1023,6 +1003,15 @@
  */
 const char *pri_facility_error2str(int facility_error_code);
 
+/*!
+ * \brief Convert the given facility reject code to a descriptive string.
+ *
+ * \param facility_reject_code Error code to convert to a string.
+ *
+ * \return Descriptive reject string.
+ */
+const char *pri_facility_reject2str(int facility_reject_code);
+
 /* Acknowledge a call and place it on the given channel.  Set info to non-zero if there
    is in-band data available on the channel */
 int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info);
@@ -1464,14 +1453,13 @@
 
 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);
+int pri_cc_req_rsp(struct pri *ctrl, long cc_id, int status);
 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);
-int pri_cc_call(struct pri *ctrl, long cc_id, q931_call *call, int channel, int exclusive);
+int pri_cc_call(struct pri *ctrl, long cc_id, q931_call *call, struct pri_sr *req);
 void pri_cc_cancel(struct pri *ctrl, long cc_id);
-int pri_cc_deactivate_req(struct pri *ctrl, long cc_id);
 
 /* Get/Set PRI Timers  */
 #define PRI_GETSET_TIMERS

Modified: team/group/ccss/pri.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri.c?view=diff&rev=1385&r1=1384&r2=1385
==============================================================================
--- team/group/ccss/pri.c (original)
+++ team/group/ccss/pri.c Sat Dec 12 02:30:21 2009
@@ -1420,8 +1420,6 @@
 		}
 	}
 
-/* BUGBUG add display of active call completion information. */
-
 	if (buf_size < used) {
 		pri_message(ctrl,
 			"pri_dump_info_str(): Produced output exceeded buffer capacity. (Truncated)\n");

Modified: team/group/ccss/pri_cc.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_cc.c?view=diff&rev=1385&r1=1384&r2=1385
==============================================================================
--- team/group/ccss/pri_cc.c (original)
+++ team/group/ccss/pri_cc.c Sat Dec 12 02:30:21 2009
@@ -599,6 +599,10 @@
  */
 static int send_ccbs_erase(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int reason)
 {
+/*
+ * XXX May need to add called-party-ie with Party A number in FACILITY message. (CCBSErase)
+ * ETSI EN 300-195-1 Section 5.41 MSN interaction.
+ */
 	if (rose_ccbs_erase_encode(ctrl, call, cc_record, reason)
 		|| q931_facility(ctrl, call)) {
 		pri_message(ctrl,
@@ -607,6 +611,40 @@
 	}
 
 	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Encode ETSI PTMP CCBSStatusRequest result 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 is_free TRUE if the Party A status is available.
+ *
+ * \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_rsp(struct pri *ctrl,
+	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record, int is_free)
+{
+	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 = cc_record->response.invoke_id;
+	msg.operation = ROSE_ETSI_CCBSStatusRequest;
+
+	msg.args.etsi.CCBSStatusRequest.free = is_free;
+
+	pos = rose_encode_result(ctrl, pos, end, &msg);
+
+	return pos;
 }
 
 /*!
@@ -738,6 +776,10 @@
  */
 static int send_ccbs_b_free(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
 {
+/*
+ * XXX May need to add called-party-ie with Party A number in FACILITY message. (CCBSBFree)
+ * ETSI EN 300-195-1 Section 5.41 MSN interaction.
+ */
 	if (rose_ccbs_b_free_encode(ctrl, call, cc_record)
 		|| q931_facility(ctrl, call)) {
 		pri_message(ctrl,
@@ -826,7 +868,7 @@
 		}
 		break;
 	case PRI_SWITCH_QSIG:
-		/* BUGBUG rose_remote_user_free_encode(Q.SIG) not written. */
+		/* \todo BUGBUG rose_remote_user_free_encode(Q.SIG) not written. */
 		return -1;
 	default:
 		return -1;
@@ -851,6 +893,10 @@
  */
 static int send_remote_user_free(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
 {
+/*
+ * XXX May need to add called-party-ie with Party A number in FACILITY message. (CCBSRemoteUserFree)
+ * ETSI EN 300-195-1 Section 5.41 MSN interaction.
+ */
 	if (rose_remote_user_free_encode(ctrl, call, cc_record, Q931_FACILITY)
 		|| q931_facility(ctrl, call)) {
 		pri_message(ctrl,
@@ -1197,6 +1243,50 @@
 }
 
 /*!
+ * \brief Respond to the received CCBSRequest/CCNRRequest invoke message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which the message came.
+ * \param invoke Decoded ROSE invoke message contents.
+ *
+ * \return Nothing
+ */
+void pri_cc_request(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
+{
+	struct pri_cc_record *cc_record;
+
+	cc_record = pri_cc_find_by_linkage(ctrl,
+		invoke->args.etsi.CCBSRequest.call_linkage_id);
+	if (!cc_record) {
+		send_facility_error(ctrl, call, invoke->invoke_id,
+			ROSE_ERROR_CCBS_InvalidCallLinkageID);
+		return;
+	}
+	if (cc_record->state != CC_STATE_AVAILABLE) {
+		send_facility_error(ctrl, call, invoke->invoke_id,
+			ROSE_ERROR_CCBS_IsAlreadyActivated);
+		return;
+	}
+	cc_record->ccbs_reference_id = pri_cc_new_reference_id(ctrl);
+	if (cc_record->ccbs_reference_id == CC_PTMP_INVALID_ID) {
+		/* Could not allocate a call reference id. */
+		send_facility_error(ctrl, call, invoke->invoke_id,
+			ROSE_ERROR_CCBS_OutgoingCCBSQueueFull);
+		return;
+	}
+
+	/* Save off data to know how to send back any response. */
+	cc_record->response.signaling = call;
+	cc_record->response.invoke_operation = invoke->operation;
+	cc_record->response.invoke_id = invoke->invoke_id;
+
+	/* Set the requested CC mode. */
+	cc_record->is_ccnr = (invoke->operation == ROSE_ETSI_CCNRRequest) ? 1 : 0;
+
+	pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST);
+}
+
+/*!
  * \internal
  * \brief Convert the given call completion state to a string.
  *
@@ -1270,8 +1360,14 @@
 	case CC_EVENT_CC_REQUEST_ACCEPT:
 		str = "CC_EVENT_CC_REQUEST_ACCEPT";
 		break;
+	case CC_EVENT_CC_REQUEST_FAIL:
+		str = "CC_EVENT_CC_REQUEST_FAIL";
+		break;
 	case CC_EVENT_REMOTE_USER_FREE:
 		str = "CC_EVENT_REMOTE_USER_FREE";
+		break;
+	case CC_EVENT_B_FREE:
+		str = "CC_EVENT_B_FREE";
 		break;
 	case CC_EVENT_A_STATUS:
 		str = "CC_EVENT_A_STATUS";
@@ -1727,6 +1823,10 @@
  */
 static int send_ccbs_status_request(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
 {
+/*
+ * XXX May need to add called-party-ie with Party A number in FACILITY message. (CCBSStatusRequest)
+ * ETSI EN 300-195-1 Section 5.41 MSN interaction.
+ */
 	if (rose_ccbs_status_request(ctrl, call, cc_record)
 		|| q931_facility(ctrl, call)) {
 		pri_message(ctrl,
@@ -1880,7 +1980,6 @@
 
 	subcmd = q931_alloc_subcommand(ctrl);
 	if (!subcmd) {
-		pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 		return;
 	}
 
@@ -1996,7 +2095,6 @@
 
 	subcmd = q931_alloc_subcommand(ctrl);
 	if (!subcmd) {
-		pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 		return;
 	}
 
@@ -2024,7 +2122,6 @@
 
 	subcmd = q931_alloc_subcommand(ctrl);
 	if (!subcmd) {
-		pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 		return;
 	}
 
@@ -2050,12 +2147,35 @@
 
 	subcmd = q931_alloc_subcommand(ctrl);
 	if (!subcmd) {
-		pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 		return;
 	}
 
 	subcmd->cmd = PRI_SUBCMD_CC_CANCEL;
 	subcmd->u.cc_cancel.cc_id =  cc_record->record_id;
+}
+
+/*!
+ * \internal
+ * \brief FSM action to pass up CC call 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_cc_call(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+	struct pri_subcommand *subcmd;
+
+	PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+
+	subcmd = q931_alloc_subcommand(ctrl);
+	if (!subcmd) {
+		return;
+	}
+
+	subcmd->cmd = PRI_SUBCMD_CC_CALL;
+	subcmd->u.cc_call.cc_id =  cc_record->record_id;
 }
 
 /*!
@@ -2153,7 +2273,6 @@
 		break;
 	case CC_EVENT_MSG_DISCONNECT:
 		pri_cc_act_send_cc_available(ctrl, call, cc_record, Q931_DISCONNECT);
-		pri_cc_act_start_t_retention(ctrl, cc_record);
 		cc_record->state = CC_STATE_AVAILABLE;
 		break;
 	case CC_EVENT_CANCEL:
@@ -2179,7 +2298,6 @@
 static void pri_cc_fsm_ptmp_agent_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
 {
 	switch (event) {
-	case CC_EVENT_MSG_DISCONNECT:
 	case CC_EVENT_MSG_RELEASE:
 	case CC_EVENT_MSG_RELEASE_COMPLETE:
 		pri_cc_act_stop_t_retention(ctrl, cc_record);
@@ -2616,6 +2734,7 @@
 		cc_record->state = CC_STATE_IDLE;
 		break;
 	case CC_EVENT_RECALL:
+		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
 		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
 		if (cc_record->option.recall_mode == 0 /* globalRecall */) {
 			pri_cc_act_send_ccbs_stop_alerting(ctrl, cc_record);
@@ -2735,6 +2854,8 @@
  *
  * \param ctrl D channel controller.
  * \param call Q.931 call leg.
+ * (May be NULL if it is supposed to be the signaling connection
+ * for Q.SIG or PTP and it is not established yet.)
  * \param cc_record Call completion record to process event.
  * \param event Event to process.
  *
@@ -2801,6 +2922,9 @@
 			? "$" : pri_cc_fsm_state_str(cc_record->state));
 	}
 	if (cc_record->fsm_complete) {
+		if (call && call->cc.record == cc_record) {
+			call->cc.record = NULL;
+		}
 		pri_cc_delete_record(ctrl, cc_record);
 		return 1;
 	} else {
@@ -2908,6 +3032,9 @@
 		return -1;
 	}
 
+	/* Set the requested CC mode. */
+	cc_record->is_ccnr = mode ? 1 : 0;
+
 	switch (ctrl->switchtype) {
 	case PRI_SWITCH_QSIG:
 		call = q931_new_call(ctrl);
@@ -2915,7 +3042,7 @@
 			return -1;
 		}
 
-/* BUGBUG */
+		/*! \todo BUGBUG pri_cc_req(Q.SIG) not written */
 		//add_qsigCcRequestArg_facility_ie(ctrl, call, Q931_SETUP, cc_record, mode);
 
 		pri_sr_init(&req);
@@ -2931,19 +3058,17 @@
 	case PRI_SWITCH_EUROISDN_E1:
 	case PRI_SWITCH_EUROISDN_T1:
 		if (q931_is_ptmp(ctrl)) {
+			pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CC_REQUEST);
 		} else {
-		}
-		return -1;
+			/*! \todo BUGBUG pri_cc_req(PTP) not written */
+			return -1;
+		}
 		break;
 	default:
 		return -1;
 	}
 
-	cc_record->state = CC_STATE_REQUESTED;
-
 	return 0;
-
-	/*! \todo BUGBUG pri_cc_req() not written */
 }
 
 /*!
@@ -3050,10 +3175,23 @@
  * \param status success(0)/timeout(1)/
  *		short_term_denial(2)/long_term_denial(3)/not_subscribed(4)/queue_full(5)
  *
- * \return Nothing
- */
-static void rose_cc_req_rsp_ptmp(struct pri *ctrl, struct pri_cc_record *cc_record, int status)
-{
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_cc_req_rsp_ptmp(struct pri *ctrl, struct pri_cc_record *cc_record, int status)
+{
+	int fail;
+
+	switch (cc_record->response.invoke_operation) {
+	case ROSE_ETSI_CCBSRequest:
+	case ROSE_ETSI_CCNRRequest:
+		break;
+	default:
+		/* We no longer know how to send the response.  Should not happen. */
+		return -1;
+	}
+
+	fail = 0;
 	if (status) {
 		enum rose_error_code code;
 
@@ -3079,12 +3217,15 @@
 			CC_EVENT_CANCEL);
 	} else {
 		/* Successful CC activation. */
-		send_cc_etsi_ptmp_req_rsp(ctrl, cc_record->response.signaling,
+		if (send_cc_etsi_ptmp_req_rsp(ctrl, cc_record->response.signaling,
 			cc_record->response.invoke_operation, cc_record->response.invoke_id,
-			cc_record->option.recall_mode, cc_record->ccbs_reference_id);
+			cc_record->option.recall_mode, cc_record->ccbs_reference_id)) {
+			fail = -1;
+		}
 		pri_cc_event(ctrl, cc_record->response.signaling, cc_record,
 			CC_EVENT_CC_REQUEST_ACCEPT);
 	}
+	return fail;
 }
 
 /*!
@@ -3097,33 +3238,41 @@
  *
  * \note
  * If the given status was failure, then the cc_id is no longer valid.
- *
- * \return Nothing
- */
-void pri_cc_req_rsp(struct pri *ctrl, long cc_id, int status)
+ * \note
+ * The caller should cancel CC if error is returned.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_cc_req_rsp(struct pri *ctrl, long cc_id, int status)
 {
 	struct pri_cc_record *cc_record;
+	int fail;
 
 	cc_record = pri_cc_find_by_id(ctrl, cc_id);
 	if (!cc_record) {
-		return;
-	}
-
+		return -1;
+	}
+
+	fail = -1;
 	switch (ctrl->switchtype) {
 	case PRI_SWITCH_QSIG:
+		/*! \todo BUGBUG pri_cc_req_rsp(Q.SIG) not written */
 		break;
 	case PRI_SWITCH_EUROISDN_E1:
 	case PRI_SWITCH_EUROISDN_T1:
 		if (q931_is_ptmp(ctrl)) {
-			rose_cc_req_rsp_ptmp(ctrl, cc_record, status);
+			if (!rose_cc_req_rsp_ptmp(ctrl, cc_record, status)) {
+				fail = 0;
+			}
 		} else {
+			/*! \todo BUGBUG pri_cc_req_rsp(PTP) not written */
 		}
 		break;
 	default:
 		break;
 	}
-
-	/*! \todo BUGBUG pri_cc_req_rsp() not written */
+	return fail;
 }
 
 /*!
@@ -3153,7 +3302,7 @@
 	is_ccbs_busy_used = 0;
 	switch (ctrl->switchtype) {
 	case PRI_SWITCH_QSIG:
-		/*! \todo BUGBUG pri_cc_remote_user_free() not written */
+		/*! \todo BUGBUG pri_cc_remote_user_free(Q.SIG) not written */
 		break;
 	case PRI_SWITCH_EUROISDN_E1:
 	case PRI_SWITCH_EUROISDN_T1:
@@ -3199,6 +3348,7 @@
 	fail = -1;
 	switch (ctrl->switchtype) {
 	case PRI_SWITCH_QSIG:
+		/* Does not apply. */
 		break;
 	case PRI_SWITCH_EUROISDN_E1:
 	case PRI_SWITCH_EUROISDN_T1:
@@ -3215,6 +3365,57 @@
 }
 
 /*!
+ * \internal
+ * \brief Encode and queue an CCBSStatusRequest result 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.
+ * \param is_free TRUE if the Party A status is available.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_ccbs_status_request_rsp(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int is_free)
+{
+	unsigned char buffer[256];
+	unsigned char *end;
+
+	end =
+		enc_etsi_ptmp_ccbs_status_request_rsp(ctrl, buffer, buffer + sizeof(buffer),
+			cc_record, is_free);
+	if (!end) {
+		return -1;
+	}
+
+	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+}
+
+/*!
+ * \internal
+ * \brief Encode and send an CCBSStatusRequest result 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.
+ * \param is_free TRUE if the Party A status is available.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_ccbs_status_request_rsp(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int is_free)
+{
+	if (rose_ccbs_status_request_rsp(ctrl, call, cc_record, is_free)
+		|| q931_facility(ctrl, call)) {
+		pri_message(ctrl,
+			"Could not schedule facility message for CCBSStatusRequest result.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
  * \brief Update the busy status of CC party A.
  *
  * \param ctrl D channel controller.
@@ -3238,18 +3439,22 @@
 
 	switch (ctrl->switchtype) {
 	case PRI_SWITCH_QSIG:
+		/* Does not apply. */
 		break;
 	case PRI_SWITCH_EUROISDN_E1:
 	case PRI_SWITCH_EUROISDN_T1:
 		if (q931_is_ptmp(ctrl)) {
-		} else {
+			if (cc_record->response.invoke_operation != ROSE_ETSI_CCBSStatusRequest) {
+				/* We no longer know how to send the response. */
+				break;
+			}
+			send_ccbs_status_request_rsp(ctrl, cc_record->signaling, cc_record,
+				status ? 0 /* busy */ : 1 /* free */);
 		}
 		break;
 	default:
 		break;
 	}
-
-	/*! \todo BUGBUG pri_cc_status_req() not written */
 }
 
 /*!
@@ -3275,18 +3480,17 @@
 
 	switch (ctrl->switchtype) {
 	case PRI_SWITCH_QSIG:
+		/*! \todo BUGBUG pri_cc_status(Q.SIG) not written */
 		break;
 	case PRI_SWITCH_EUROISDN_E1:
 	case PRI_SWITCH_EUROISDN_T1:
-		if (q931_is_ptmp(ctrl)) {
-		} else {
+		if (!q931_is_ptmp(ctrl)) {
+			/*! \todo BUGBUG pri_cc_status(PTP) not written */
 		}
 		break;
 	default:
 		break;
 	}
-
-	/*! \todo BUGBUG pri_cc_status() not written */
 }
 
 /*!
@@ -3295,13 +3499,12 @@
  * \param ctrl D channel controller.
  * \param cc_id CC record ID to activate.
  * \param call Q.931 call leg.
- * \param channel Encoded B channel to use.
- * \param exclusive TRUE if the specified B channel must be used.
+ * \param req SETUP request parameters.  Parameters saved by CC will override.
  *
  * \retval 0 on success.
  * \retval -1 on error.
  */
-int pri_cc_call(struct pri *ctrl, long cc_id, q931_call *call, int channel, int exclusive)
+int pri_cc_call(struct pri *ctrl, long cc_id, q931_call *call, struct pri_sr *req)
 {
 	struct pri_cc_record *cc_record;
 
@@ -3310,21 +3513,27 @@
 		return -1;
 	}
 
-	switch (ctrl->switchtype) {
-	case PRI_SWITCH_QSIG:
-		break;
-	case PRI_SWITCH_EUROISDN_E1:
-	case PRI_SWITCH_EUROISDN_T1:
-		if (q931_is_ptmp(ctrl)) {
-		} else {
-		}
-		break;
-	default:
-		break;
-	}
-
-	/*! \todo BUGBUG pri_cc_call() not written */
-	return -1;
+	/* Override parameters for sending recall. */
+	req->caller = cc_record->party_a;
+	req->called = cc_record->party_b;
+	req->transmode = cc_record->bc.transcapability;
+	req->userl1 = cc_record->bc.userl1;
+
+	/*
+	 * The caller is allowed to send different user-user information.
+	 *
+	 * It makes no sense for the caller to supply redirecting information
+	 * but we'll allow it to pass anyway.
+	 */
+	//q931_party_redirecting_init(&req->redirecting);
+
+	/* Add switch specific recall APDU to call. */
+	pri_cc_event(ctrl, call, cc_record, CC_EVENT_RECALL);
+
+	if (q931_setup(ctrl, call, req)) {
+		return -1;
+	}
+	return 0;
 }
 
 /*!
@@ -3346,45 +3555,5 @@
 	pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CANCEL);
 }
 
-/*!
- * \brief Request that the CC be canceled.
- *
- * \param ctrl D channel controller.
- * \param cc_id CC record ID to request deactivation.
- *
- * \note
- * Will always get a PRI_SUBCMD_CC_DEACTIVATE_RSP from libpri.
- * \note
- * Deactivate is used in the party A to party B direction if a response is needed.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int pri_cc_deactivate_req(struct pri *ctrl, long cc_id)
-{
-	struct pri_cc_record *cc_record;
-
-	cc_record = pri_cc_find_by_id(ctrl, cc_id);
-	if (!cc_record) {
-		return -1;
-	}
-
-	switch (ctrl->switchtype) {
-	case PRI_SWITCH_QSIG:
-		break;
-	case PRI_SWITCH_EUROISDN_E1:
-	case PRI_SWITCH_EUROISDN_T1:
-		if (q931_is_ptmp(ctrl)) {
-		} else {
-		}
-		break;
-	default:
-		break;
-	}
-
-	/*! \todo BUGBUG pri_cc_deactivate_req() not written */
-	return -1;
-}
-
 /* ------------------------------------------------------------------- */
 /* end pri_cc.c */

Modified: team/group/ccss/pri_facility.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_facility.c?view=diff&rev=1385&r1=1384&r2=1385
==============================================================================
--- team/group/ccss/pri_facility.c (original)
+++ team/group/ccss/pri_facility.c Sat Dec 12 02:30:21 2009
@@ -40,6 +40,11 @@
 const char *pri_facility_error2str(int facility_error_code)
 {
 	return rose_error2str(facility_error_code);
+}
+
+const char *pri_facility_reject2str(int facility_reject_code)
+{
+	return rose_reject2str(facility_reject_code);
 }
 
 static int redirectingreason_from_q931(struct pri *ctrl, int redirectingreason)
@@ -3545,7 +3550,6 @@
 			 */
 			send_facility_error(ctrl, call, invoke->invoke_id,
 				ROSE_ERROR_Gen_ResourceUnavailable);
-			pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 			break;
 		}
 
@@ -3598,7 +3602,6 @@
 		if (!subcmd) {
 			send_facility_error(ctrl, call, invoke->invoke_id,
 				ROSE_ERROR_Gen_ResourceUnavailable);
-			pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 			break;
 		}
 
@@ -3751,7 +3754,6 @@
 			call->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
 			subcmd = q931_alloc_subcommand(ctrl);
 			if (!subcmd) {
-				pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 				break;
 			}
 			/* Setup redirecting subcommand */
@@ -3839,6 +3841,7 @@
 #endif	/* Not handled yet */
 #if 0	/* Not handled yet */
 	case ROSE_ETSI_StatusRequest:
+		/*! \todo BUGBUG ROSE_ETSI_StatusRequest not handled */
 		break;
 #endif	/* Not handled yet */
 	case ROSE_ETSI_CallInfoRetain:
@@ -3864,47 +3867,24 @@
 		cc_record->signaling = PRI_MASTER(ctrl)->dummy_call;
 		cc_record->call_linkage_id =
 			invoke->args.etsi.CallInfoRetain.call_linkage_id & 0x7F;
-		if (pri_cc_event(ctrl, call, cc_record, CC_EVENT_AVAILABLE)) {
-			break;
-		}
-
+		call->cc.record = cc_record;
+		pri_cc_event(ctrl, call, cc_record, CC_EVENT_AVAILABLE);
+
+/* BUGBUG move to pri_cc_act_pass_up_cc_available() --v */
 		subcmd = q931_alloc_subcommand(ctrl);
 		if (!subcmd) {
-			pri_cc_event(ctrl, call, cc_record, CC_EVENT_CANCEL);
-			pri_error(ctrl, "ERROR: Too many facility subcommands\n");
-			break;
-		}
-		call->cc.record = cc_record;
+			break;
+		}
 
 		subcmd->cmd = PRI_SUBCMD_CC_AVAILABLE;
 		subcmd->u.cc_available.cc_id = cc_record->record_id;
+/* BUGBUG move to pri_cc_act_pass_up_cc_available() --^ */
 		break;
 	case ROSE_ETSI_CCBSRequest:
-		cc_record = pri_cc_find_by_linkage(ctrl,
-			invoke->args.etsi.CCBSRequest.call_linkage_id);
-		if (!cc_record) {
-			send_facility_error(ctrl, call, invoke->invoke_id,
-				ROSE_ERROR_CCBS_InvalidCallLinkageID);
-			break;
-		}
-		if (cc_record->state != CC_STATE_AVAILABLE) {
-			send_facility_error(ctrl, call, invoke->invoke_id,
-				ROSE_ERROR_CCBS_IsAlreadyActivated);
-			break;
-		}
-		cc_record->ccbs_reference_id = pri_cc_new_reference_id(ctrl);
-		if (cc_record->ccbs_reference_id == CC_PTMP_INVALID_ID) {
-			/* Could not allocate a call reference id. */
-			send_facility_error(ctrl, call, invoke->invoke_id,
-				ROSE_ERROR_CCBS_OutgoingCCBSQueueFull);
-			break;
-		}
-
-		cc_record->response.signaling = call;
-		cc_record->response.invoke_operation = invoke->operation;
-		cc_record->response.invoke_id = invoke->invoke_id;
-		cc_record->is_ccnr = 0;/* ccbs */
-		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST);
+		pri_cc_request(ctrl, call, invoke);
+		break;
+	case ROSE_ETSI_CCNRRequest:
+		pri_cc_request(ctrl, call, invoke);
 		break;
 	case ROSE_ETSI_CCBSDeactivate:
 		cc_record = pri_cc_find_by_reference(ctrl,
@@ -3920,9 +3900,34 @@
 	case ROSE_ETSI_CCBSInterrogate:
 		pri_cc_interrogate_rsp(ctrl, call, invoke);
 		break;
+	case ROSE_ETSI_CCNRInterrogate:
+		pri_cc_interrogate_rsp(ctrl, call, invoke);
+		break;
 	case ROSE_ETSI_CCBSErase:
+		cc_record = pri_cc_find_by_reference(ctrl,
+			invoke->args.etsi.CCBSErase.ccbs_reference);
+		if (!cc_record) {
+			/*
+			 * Ignore any status requests that we do not have a record.
+			 * We will not participate in any CC requests that we did
+			 * not initiate.
+			 */
+			break;
+		}
+		pri_cc_event(ctrl, call, cc_record, CC_EVENT_LINK_CANCEL);
 		break;
 	case ROSE_ETSI_CCBSRemoteUserFree:
+		cc_record = pri_cc_find_by_reference(ctrl,
+			invoke->args.etsi.CCBSRemoteUserFree.ccbs_reference);
+		if (!cc_record) {
+			/*
+			 * Ignore any status requests that we do not have a record.
+			 * We will not participate in any CC requests that we did
+			 * not initiate.
+			 */
+			break;
+		}
+		pri_cc_event(ctrl, call, cc_record, CC_EVENT_REMOTE_USER_FREE);
 		break;
 	case ROSE_ETSI_CCBSCall:
 		cc_record = pri_cc_find_by_reference(ctrl,
@@ -3934,20 +3939,91 @@
 			break;
 		}
 
+		/* Save off data to know how to send back any response. */
 		cc_record->response.signaling = call;
 		cc_record->response.invoke_operation = invoke->operation;
 		cc_record->response.invoke_id = invoke->invoke_id;
+
 		pri_cc_event(ctrl, call, cc_record, CC_EVENT_RECALL);
 		break;
 	case ROSE_ETSI_CCBSStatusRequest:
+		cc_record = pri_cc_find_by_reference(ctrl,
+			invoke->args.etsi.CCBSStatusRequest.ccbs_reference);
+		if (!cc_record) {
+			/*
+			 * Ignore any status requests that we do not have a record.
+			 * We will not participate in any CC requests that we did
+			 * not initiate.
+			 */
+			break;
+		}
+
+		/* Save off data to know how to send back any response. */
+		cc_record->response.signaling = call;
+		cc_record->response.invoke_operation = invoke->operation;
+		cc_record->response.invoke_id = invoke->invoke_id;
+
+		subcmd = q931_alloc_subcommand(ctrl);
+		if (!subcmd) {
+			break;
+		}
+
+		subcmd->cmd = PRI_SUBCMD_CC_STATUS_REQ;
+		subcmd->u.cc_status_req.cc_id = cc_record->record_id;
 		break;
 	case ROSE_ETSI_CCBSBFree:
+		cc_record = pri_cc_find_by_reference(ctrl,
+			invoke->args.etsi.CCBSBFree.ccbs_reference);
+		if (!cc_record) {
+			/*
+			 * Ignore any status requests that we do not have a record.
+			 * We will not participate in any CC requests that we did
+			 * not initiate.
+			 */
+			break;
+		}
+		pri_cc_event(ctrl, call, cc_record, CC_EVENT_B_FREE);
 		break;
 	case ROSE_ETSI_EraseCallLinkageID:
+		cc_record = pri_cc_find_by_linkage(ctrl,
+			invoke->args.etsi.EraseCallLinkageID.call_linkage_id);
+		if (!cc_record) {
+			/*
+			 * Ignore any status requests that we do not have a record.
+			 * We will not participate in any CC requests that we did
+			 * not initiate.
+			 */
+			break;
+		}
+		/*
+		 * T_RETENTION expired on the network side so we will pretend
+		 * that it expired on our side.
+		 */
+		pri_cc_event(ctrl, call, cc_record, CC_EVENT_TIMEOUT_T_RETENTION);
 		break;
 	case ROSE_ETSI_CCBSStopAlerting:
+		cc_record = pri_cc_find_by_reference(ctrl,
+			invoke->args.etsi.CCBSStopAlerting.ccbs_reference);
+		if (!cc_record) {
+			/*
+			 * Ignore any status requests that we do not have a record.
+			 * We will not participate in any CC requests that we did
+			 * not initiate.
+			 */
+			break;
+		}
+
+		subcmd = q931_alloc_subcommand(ctrl);
+		if (!subcmd) {
+			break;
+		}
+
+		subcmd->cmd = PRI_SUBCMD_CC_STOP_ALERTING;
+		subcmd->u.cc_stop_alerting.cc_id = cc_record->record_id;
 		break;
 	case ROSE_ETSI_CCBS_T_Request:
+		break;
+	case ROSE_ETSI_CCNR_T_Request:
 		break;
 	case ROSE_ETSI_CCBS_T_Call:
 		break;
@@ -3973,52 +4049,8 @@
 		if (!cc_record) {
 			break;
 		}
-		if (pri_cc_event(ctrl, call, cc_record, CC_EVENT_AVAILABLE)) {
-			break;
-		}
-
-		subcmd = q931_alloc_subcommand(ctrl);
-		if (!subcmd) {
-			pri_cc_event(ctrl, call, cc_record, CC_EVENT_CANCEL);
-			pri_error(ctrl, "ERROR: Too many facility subcommands\n");
-			break;
-		}
 		call->cc.record = cc_record;
-
-		subcmd->cmd = PRI_SUBCMD_CC_AVAILABLE;
-		subcmd->u.cc_available.cc_id = cc_record->record_id;
-		break;
-	case ROSE_ETSI_CCNRRequest:
-		cc_record = pri_cc_find_by_linkage(ctrl,
-			invoke->args.etsi.CCNRRequest.call_linkage_id);
-		if (!cc_record) {
-			send_facility_error(ctrl, call, invoke->invoke_id,
-				ROSE_ERROR_CCBS_InvalidCallLinkageID);
-			break;
-		}
-		if (cc_record->state != CC_STATE_AVAILABLE) {
-			send_facility_error(ctrl, call, invoke->invoke_id,
-				ROSE_ERROR_CCBS_IsAlreadyActivated);
-			break;
-		}
-		cc_record->ccbs_reference_id = pri_cc_new_reference_id(ctrl);
-		if (cc_record->ccbs_reference_id == CC_PTMP_INVALID_ID) {
-			/* Could not allocate a call reference id. */
-			send_facility_error(ctrl, call, invoke->invoke_id,
-				ROSE_ERROR_CCBS_OutgoingCCBSQueueFull);
-			break;
-		}
-
-		cc_record->response.signaling = call;
-		cc_record->response.invoke_operation = invoke->operation;
-		cc_record->response.invoke_id = invoke->invoke_id;
-		cc_record->is_ccnr = 1;/* ccnr */
-		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST);
-		break;
-	case ROSE_ETSI_CCNRInterrogate:
-		pri_cc_interrogate_rsp(ctrl, call, invoke);
-		break;
-	case ROSE_ETSI_CCNR_T_Request:
+		pri_cc_event(ctrl, call, cc_record, CC_EVENT_AVAILABLE);
 		break;
 	case ROSE_QSIG_CallingName:
 		/* CallingName is put in remote_id.name */
@@ -4033,7 +4065,6 @@
 		/* Setup connected line subcommand */
 		subcmd = q931_alloc_subcommand(ctrl);
 		if (!subcmd) {
-			pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 			break;
 		}
 		subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE;
@@ -4157,7 +4188,6 @@
 		if (!subcmd) {
 			send_facility_error(ctrl, call, invoke->invoke_id,
 				ROSE_ERROR_Gen_ResourceUnavailable);
-			pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 			break;
 		}
 
@@ -4351,7 +4381,6 @@
 			call->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
 			subcmd = q931_alloc_subcommand(ctrl);
 			if (!subcmd) {
-				pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 				break;
 			}
 			/* Setup redirecting subcommand */

Modified: team/group/ccss/pri_facility.h
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_facility.h?view=diff&rev=1385&r1=1384&r2=1385
==============================================================================
--- team/group/ccss/pri_facility.h (original)
+++ team/group/ccss/pri_facility.h Sat Dec 12 02:30:21 2009
@@ -229,5 +229,6 @@
 void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_reject *reject);
 
 int pri_cc_interrogate_rsp(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke);
+void pri_cc_request(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke);
 
 #endif /* _PRI_FACILITY_H */

Modified: team/group/ccss/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_internal.h?view=diff&rev=1385&r1=1384&r2=1385
==============================================================================
--- team/group/ccss/pri_internal.h (original)
+++ team/group/ccss/pri_internal.h Sat Dec 12 02:30:21 2009
@@ -650,8 +650,12 @@
 	CC_EVENT_CC_REQUEST,
 	/*! Requesting CC activation accepted. */
 	CC_EVENT_CC_REQUEST_ACCEPT,
+	/*! Requesting CC activation failed (error/reject received). */
+	CC_EVENT_CC_REQUEST_FAIL,
 	/*! CC party B is available. */
 	CC_EVENT_REMOTE_USER_FREE,
+	/*! CC party B is available, party A is busy or CCBS busy. */
+	CC_EVENT_B_FREE,
 	/*! CC poll/prompt for party A status. */
 	CC_EVENT_A_STATUS,
 	/*! CC party A is free/available for recall. */

Modified: team/group/ccss/q931.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/q931.c?view=diff&rev=1385&r1=1384&r2=1385
==============================================================================
--- team/group/ccss/q931.c (original)
+++ team/group/ccss/q931.c Sat Dec 12 02:30:21 2009
@@ -900,6 +900,7 @@
 		return &ctrl->subcmds.subcmd[ctrl->subcmds.counter_subcmd++];
 	}
 
+	pri_error(ctrl, "ERROR: Too many facility subcommands\n");
 	return NULL;
 }
 




More information about the libpri-commits mailing list