[libpri-commits] rmudgett: branch group/ccss r1393 - in /team/group/ccss: ./ doc/

SVN commits to the libpri project libpri-commits at lists.digium.com
Fri Dec 18 22:42:41 CST 2009


Author: rmudgett
Date: Fri Dec 18 22:42:38 2009
New Revision: 1393

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1393
Log:
PTP agent FSM written.  Needs testing.

*  Added CC PTP agent FSM pseudo code document files in the doc directory.
*  Changed PRI_SUBCMD_CC_REQ_RSP to include the negotiated retain service
flag.
*  Added cis_recognized flag to automatically drop incoming CIS calls if
they are not handled/recognized by us.  This is a safeguard to prevent a
resource drain if we do not recognize the supplementary service the CIS
connection supports.

Added:
    team/group/ccss/doc/cc_ptp_agent.fsm   (with props)
    team/group/ccss/doc/cc_ptp_agent_flattened.fsm   (with props)
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/q931.c

Added: team/group/ccss/doc/cc_ptp_agent.fsm
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/doc/cc_ptp_agent.fsm?view=auto&rev=1393
==============================================================================
--- team/group/ccss/doc/cc_ptp_agent.fsm (added)
+++ team/group/ccss/doc/cc_ptp_agent.fsm Fri Dec 18 22:42:38 2009
@@ -1,0 +1,162 @@
+/*
+ * FSM pseudo code used in the design/implementation of the CC PTP agent.
+ */
+FSM CC_PTP_Agent
+{
+	State CC_STATE_IDLE {
+		Init {
+		}
+		Prolog {
+			Action Set_Selfdestruct;
+		}
+		Stimulus CC_EVENT_AVAILABLE {
+			Next_State CC_STATE_PENDING_AVAILABLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Set_Selfdestruct;
+		}
+	}
+	State CC_STATE_PENDING_AVAILABLE {
+		Stimulus CC_EVENT_MSG_ALERTING {
+			Action Send_CC_Available(Q931_ALERTING);
+			Next_State CC_STATE_AVAILABLE;
+		}
+		Stimulus CC_EVENT_MSG_DISCONNECT {
+			Action Send_CC_Available(Q931_DISCONNECT);
+			Next_State CC_STATE_AVAILABLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_AVAILABLE {
+		/*
+		 * For PTP mode the T_RETENTION timer is not defined.  However,
+		 * we will use it anyway in this state to protect our resources
+		 * from leaks caused by user A not requesting CC.  This timer
+		 * should be set much longer than the PTMP network link to
+		 * allow for variations in user A's CC offer timer.
+		 */
+		Epilog {
+			Action Stop_T_RETENTION;
+		}
+		Stimulus CC_EVENT_MSG_RELEASE {
+			Action Stop_T_RETENTION;
+			Action Start_T_RETENTION;
+		}
+		Stimulus CC_EVENT_MSG_RELEASE_COMPLETE {
+			Action Stop_T_RETENTION;
+			Action Start_T_RETENTION;
+		}
+		Stimulus CC_EVENT_CC_REQUEST {
+			Action Pass_Up_CC_Request;
+			Action Stop_T_RETENTION;
+			Next_State CC_STATE_REQUESTED;
+		}
+		Stimulus CC_EVENT_TIMEOUT_T_RETENTION {
+			Action Pass_Up_CC_Cancel;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_REQUESTED {
+		Stimulus CC_EVENT_CC_REQUEST_ACCEPT {
+			Next_State CC_STATE_ACTIVATED;
+		}
+		Stimulus CC_EVENT_SIGNALING_GONE {
+			/* Signaling link cleared. */
+			Action Pass_Up_CC_Cancel;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Hangup_Signaling_Link;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_WAIT_DESTRUCTION {
+		/*
+		 * Delayed disconnect of the signaling link to allow subcmd events
+		 * from the signaling link to be passed up.
+		 */
+		Stimulus CC_EVENT_SIGNALING_GONE {
+			/* Signaling link cleared. */
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_HANGUP_SIGNALING {
+			Action Hangup_Signaling_Link;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Hangup_Signaling_Link;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_ACTIVATED {
+		Prolog {
+			Action Reset_A_Status;
+		}
+		Stimulus CC_EVENT_REMOTE_USER_FREE {
+			Action Pass_Up_A_Status;
+			Test = Get_A_Status;
+			Test == Busy {
+				Next_State CC_STATE_SUSPENDED;
+			}
+			Action Send_RemoteUserFree;
+			Next_State CC_STATE_WAIT_CALLBACK;
+		}
+		Stimulus CC_EVENT_SUSPEND {
+			/* Received CCBS_T_Suspend */
+			Action Set_A_Status_Busy;
+		}
+		Stimulus CC_EVENT_RESUME {
+			/* Received CCBS_T_Resume */
+			Action Reset_A_Status;
+		}
+	}
+	State CC_STATE_WAIT_CALLBACK {
+		Stimulus CC_EVENT_SUSPEND {
+			/* Received CCBS_T_Suspend */
+			Action Set_A_Status_Busy;
+			Action Pass_Up_A_Status;
+			Next_State CC_STATE_SUSPENDED;
+		}
+	}
+	State CC_STATE_SUSPENDED {
+		Stimulus CC_EVENT_RESUME {
+			/* Received CCBS_T_Resume */
+			Action Set_A_Status_Free;
+			Action Pass_Up_A_Status;
+			Next_State CC_STATE_ACTIVATED;
+		}
+	}
+	Superstate CC_ACTIVE(CC_STATE_ACTIVATED, CC_STATE_WAIT_CALLBACK, CC_STATE_SUSPENDED) {
+		Prolog {
+			/* Start T_CCBS5/T_CCNR5 depending upon CC mode. */
+			Action Start_T_SUPERVISION;
+		}
+		Epilog {
+			Action Stop_T_SUPERVISION;
+		}
+		Stimulus CC_EVENT_RECALL {
+			/* Received CCBS_T_Call */
+			Action Pass_Up_CC_Call;
+			Action Set_Original_Call_Parameters;
+		}
+		Stimulus CC_EVENT_TIMEOUT_T_SUPERVISION {
+			Action Pass_Up_CC_Cancel;
+			Action Post_HANGUP_SIGNALING;
+			Next_State CC_STATE_WAIT_DESTRUCTION;
+		}
+		Stimulus CC_EVENT_SIGNALING_GONE {
+			/* Signaling link cleared. */
+			Action Pass_Up_CC_Cancel;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Hangup_Signaling_Link;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+}

Propchange: team/group/ccss/doc/cc_ptp_agent.fsm
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/ccss/doc/cc_ptp_agent.fsm
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/ccss/doc/cc_ptp_agent.fsm
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/group/ccss/doc/cc_ptp_agent_flattened.fsm
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/doc/cc_ptp_agent_flattened.fsm?view=auto&rev=1393
==============================================================================
--- team/group/ccss/doc/cc_ptp_agent_flattened.fsm (added)
+++ team/group/ccss/doc/cc_ptp_agent_flattened.fsm Fri Dec 18 22:42:38 2009
@@ -1,0 +1,209 @@
+/*
+ * FSM pseudo code used in the design/implementation of the CC PTP agent.
+ */
+FSM CC_PTP_Agent
+{
+	State CC_STATE_IDLE {
+		Stimulus CC_EVENT_AVAILABLE {
+			Next_State CC_STATE_PENDING_AVAILABLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Set_Selfdestruct;
+		}
+	}
+	State CC_STATE_PENDING_AVAILABLE {
+		Stimulus CC_EVENT_MSG_ALERTING {
+			Action Send_CC_Available(Q931_ALERTING);
+			Next_State CC_STATE_AVAILABLE;
+		}
+		Stimulus CC_EVENT_MSG_DISCONNECT {
+			Action Send_CC_Available(Q931_DISCONNECT);
+			Next_State CC_STATE_AVAILABLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_AVAILABLE {
+		/*
+		 * For PTP mode the T_RETENTION timer is not defined.  However,
+		 * we will use it anyway in this state to protect our resources
+		 * from leaks caused by user A not requesting CC.  This timer
+		 * should be set much longer than the PTMP network link to
+		 * allow for variations in user A's CC offer timer.
+		 */
+		Stimulus CC_EVENT_MSG_RELEASE {
+			Action Stop_T_RETENTION;
+			Action Start_T_RETENTION;
+		}
+		Stimulus CC_EVENT_MSG_RELEASE_COMPLETE {
+			Action Stop_T_RETENTION;
+			Action Start_T_RETENTION;
+		}
+		Stimulus CC_EVENT_CC_REQUEST {
+			Action Pass_Up_CC_Request;
+			Action Stop_T_RETENTION;
+			Next_State CC_STATE_REQUESTED;
+		}
+		Stimulus CC_EVENT_TIMEOUT_T_RETENTION {
+			Action Pass_Up_CC_Cancel;
+			Action Stop_T_RETENTION;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Stop_T_RETENTION;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_REQUESTED {
+		Stimulus CC_EVENT_CC_REQUEST_ACCEPT {
+			/* Start T_CCBS5/T_CCNR5 depending upon CC mode. */
+			Action Start_T_SUPERVISION;
+			Action Reset_A_Status;
+			Next_State CC_STATE_ACTIVATED;
+		}
+		Stimulus CC_EVENT_SIGNALING_GONE {
+			/* Signaling link cleared. */
+			Action Pass_Up_CC_Cancel;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Hangup_Signaling_Link;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_WAIT_DESTRUCTION {
+		/*
+		 * Delayed disconnect of the signaling link to allow subcmd events
+		 * from the signaling link to be passed up.
+		 */
+		Stimulus CC_EVENT_SIGNALING_GONE {
+			/* Signaling link cleared. */
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_HANGUP_SIGNALING {
+			Action Hangup_Signaling_Link;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Hangup_Signaling_Link;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_ACTIVATED {
+		Stimulus CC_EVENT_REMOTE_USER_FREE {
+			Action Pass_Up_A_Status;
+			Test = Get_A_Status;
+			Test == Busy {
+				Next_State CC_STATE_SUSPENDED;
+			}
+			Action Send_RemoteUserFree;
+			Next_State CC_STATE_WAIT_CALLBACK;
+		}
+		Stimulus CC_EVENT_SUSPEND {
+			/* Received CCBS_T_Suspend */
+			Action Set_A_Status_Busy;
+		}
+		Stimulus CC_EVENT_RESUME {
+			/* Received CCBS_T_Resume */
+			Action Reset_A_Status;
+		}
+		Stimulus CC_EVENT_RECALL {
+			/* Received CCBS_T_Call */
+			Action Pass_Up_CC_Call;
+			Action Set_Original_Call_Parameters;
+		}
+		Stimulus CC_EVENT_TIMEOUT_T_SUPERVISION {
+			Action Pass_Up_CC_Cancel;
+			Action Post_HANGUP_SIGNALING;
+			Action Stop_T_SUPERVISION;
+			Next_State CC_STATE_WAIT_DESTRUCTION;
+		}
+		Stimulus CC_EVENT_SIGNALING_GONE {
+			/* Signaling link cleared. */
+			Action Pass_Up_CC_Cancel;
+			Action Stop_T_SUPERVISION;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Hangup_Signaling_Link;
+			Action Stop_T_SUPERVISION;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_WAIT_CALLBACK {
+		Stimulus CC_EVENT_SUSPEND {
+			/* Received CCBS_T_Suspend */
+			Action Set_A_Status_Busy;
+			Action Pass_Up_A_Status;
+			Next_State CC_STATE_SUSPENDED;
+		}
+		Stimulus CC_EVENT_RECALL {
+			/* Received CCBS_T_Call */
+			Action Pass_Up_CC_Call;
+			Action Set_Original_Call_Parameters;
+		}
+		Stimulus CC_EVENT_TIMEOUT_T_SUPERVISION {
+			Action Pass_Up_CC_Cancel;
+			Action Post_HANGUP_SIGNALING;
+			Action Stop_T_SUPERVISION;
+			Next_State CC_STATE_WAIT_DESTRUCTION;
+		}
+		Stimulus CC_EVENT_SIGNALING_GONE {
+			/* Signaling link cleared. */
+			Action Pass_Up_CC_Cancel;
+			Action Stop_T_SUPERVISION;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Hangup_Signaling_Link;
+			Action Stop_T_SUPERVISION;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+	State CC_STATE_SUSPENDED {
+		Stimulus CC_EVENT_RESUME {
+			/* Received CCBS_T_Resume */
+			Action Set_A_Status_Free;
+			Action Pass_Up_A_Status;
+			Action Reset_A_Status;
+			Next_State CC_STATE_ACTIVATED;
+		}
+		Stimulus CC_EVENT_RECALL {
+			/* Received CCBS_T_Call */
+			Action Pass_Up_CC_Call;
+			Action Set_Original_Call_Parameters;
+		}
+		Stimulus CC_EVENT_TIMEOUT_T_SUPERVISION {
+			Action Pass_Up_CC_Cancel;
+			Action Post_HANGUP_SIGNALING;
+			Action Stop_T_SUPERVISION;
+			Next_State CC_STATE_WAIT_DESTRUCTION;
+		}
+		Stimulus CC_EVENT_SIGNALING_GONE {
+			/* Signaling link cleared. */
+			Action Pass_Up_CC_Cancel;
+			Action Stop_T_SUPERVISION;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+		Stimulus CC_EVENT_CANCEL {
+			Action Hangup_Signaling_Link;
+			Action Stop_T_SUPERVISION;
+			Action Set_Selfdestruct;
+			Next_State CC_STATE_IDLE;
+		}
+	}
+}

Propchange: team/group/ccss/doc/cc_ptp_agent_flattened.fsm
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/ccss/doc/cc_ptp_agent_flattened.fsm
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/ccss/doc/cc_ptp_agent_flattened.fsm
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/group/ccss/libpri.h
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/libpri.h?view=diff&rev=1393&r1=1392&r2=1393
==============================================================================
--- team/group/ccss/libpri.h (original)
+++ team/group/ccss/libpri.h Fri Dec 18 22:42:38 2009
@@ -575,6 +575,11 @@
 	 * ccnr(1)
 	 */
 	int mode;
+	/*!
+	 * \brief TRUE if negotiated to retain CC service if B busy again.
+	 * \note This will be the setting if the CC request is accepted.
+	 */
+	int retain_service;
 };
 
 struct pri_subcmd_cc_request_rsp {
@@ -1413,7 +1418,8 @@
 void pri_cc_recall_mode(struct pri *ctrl, int mode);
 
 /*!
- * \brief Set the call completion service retention mode if party B is busy again.
+ * \brief Set the call completion service retention mode to negotiate
+ * if party B is busy again.
  *
  * \param ctrl D channel controller.
  * \param retain_service TRUE if can retain cc service if party B is unavailable again.

Modified: team/group/ccss/pri_cc.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_cc.c?view=diff&rev=1393&r1=1392&r2=1393
==============================================================================
--- team/group/ccss/pri_cc.c (original)
+++ team/group/ccss/pri_cc.c Fri Dec 18 22:42:38 2009
@@ -116,32 +116,134 @@
 }
 
 /*!
+ * \internal
+ * \brief Find the given ie_type in the string of q931 ies.
+ *
+ * \param ie_type Q.931 ie type to find in q931_ies.
+ * \param length Length of the given q931_ies
+ * \param q931_ies Given q931_ies
+ *
+ * \retval found-ie on success.
+ * \retval NULL on error.
+ */
+static const struct q931_ie *pri_cc_find_ie(unsigned ie_type, unsigned length, const unsigned char *q931_ies)
+{
+	const unsigned char *pos;
+	const unsigned char *end;
+	const unsigned char *next;
+	const struct q931_ie *cur;
+
+	end = q931_ies + length;
+	for (pos = q931_ies; pos < end; pos = next) {
+		cur = (const struct q931_ie *) pos;
+		if (cur->ie & 0x80) {
+			/* Single octet ie. */
+			next = pos + 1;
+		} else {
+			/* Variable length ie. */
+			next = cur->data + cur->len;
+		}
+		if (cur->ie == ie_type && next <= end) {
+			/* Found the ie and it is within the given q931_ies body. */
+			return cur;
+		}
+	}
+	return NULL;
+}
+
+/*!
+ * \internal
+ * \brief Compare the specified ie type in the CC record q931_ies to the given q931_ies.
+ *
+ * \details
+ * The individual q931 ie is compared with memcmp().
+ *
+ * \param ie_type Q.931 ie type to compare.
+ * \param record_ies CC record q931_ies
+ * \param length Length of the given q931_ies
+ * \param q931_ies Given q931_ies
+ *
+ * \retval == 0 when record_ies == q931_ies.
+ * \retval != 0 when record_ies != q931_ies.
+ */
+static int pri_cc_cmp_ie(unsigned ie_type, const struct q931_saved_ie_contents *record_ies, unsigned length, const unsigned char *q931_ies)
+{
+	const struct q931_ie *left;
+	const struct q931_ie *right;
+
+	left = pri_cc_find_ie(ie_type, record_ies->length, record_ies->data);
+	right = pri_cc_find_ie(ie_type, length, q931_ies);
+
+	if (!left && !right) {
+		/* Neither has the requested ie to compare so they match. */
+		return 0;
+	}
+	if (!left || !right) {
+		/* One or the other does not have the requested ie to compare. */
+		return 1;
+	}
+	if (left->len != right->len) {
+		/* They are not the same length. */
+		return 1;
+	}
+	return memcmp(left->data, right->data, right->len);
+}
+
+/*!
+ * \internal
+ * \brief Compare the CC record q931_ies to the given q931_ies.
+ *
+ * \note
+ * Only the first BC, HLC, and LLC ies in the given q931_ies are compared.
+ *
+ * \param record_ies CC record q931_ies
+ * \param length Length of the given q931_ies
+ * \param q931_ies Given q931_ies
+ *
+ * \retval == 0 when record_ies == q931_ies.
+ * \retval != 0 when record_ies != q931_ies.
+ */
+static int pri_cc_cmp_q931_ies(const struct q931_saved_ie_contents *record_ies, unsigned length, const unsigned char *q931_ies)
+{
+	return pri_cc_cmp_ie(Q931_BEARER_CAPABILITY, record_ies, length, q931_ies)
+		|| pri_cc_cmp_ie(Q931_HIGH_LAYER_COMPAT, record_ies, length, q931_ies)
+		|| pri_cc_cmp_ie(Q931_LOW_LAYER_COMPAT, record_ies, length, q931_ies);
+}
+
+/*!
  * \brief Find a cc_record by an incoming call addressing data.
  *
  * \param ctrl D channel controller.
  * \param party_a Party A address.
  * \param party_b Party B address.
+ * \param length Length of the given q931_ies.
+ * \param q931_ies BC, HLC, LLC ies to compare with CC records.
  *
  * \retval cc_record on success.
  * \retval NULL on error.
  */
-struct pri_cc_record *pri_cc_find_by_addressing(struct pri *ctrl, const struct q931_party_address *party_a, const struct q931_party_address *party_b)
+struct pri_cc_record *pri_cc_find_by_addressing(struct pri *ctrl, const struct q931_party_address *party_a, const struct q931_party_address *party_b, unsigned length, const unsigned char *q931_ies)
 {
 	struct pri_cc_record *cc_record;
+	struct q931_party_address addr_a;
+	struct q931_party_address addr_b;
 
 	ctrl = PRI_MASTER(ctrl);
+	addr_a = *party_a;
+	addr_b = *party_b;
 	for (cc_record = ctrl->cc.pool; cc_record; cc_record = cc_record->next) {
-		if (!q931_cmp_party_id_to_address(&cc_record->party_a, party_a)
-			&& !q931_party_address_cmp(&cc_record->party_b, party_b)) {
+		/* Do not compare the number presentation. */
+		addr_a.number.presentation = cc_record->party_a.number.presentation;
+		addr_b.number.presentation = cc_record->party_b.number.presentation;
+		if (!q931_cmp_party_id_to_address(&cc_record->party_a, &addr_a)
+			&& !q931_party_address_cmp(&cc_record->party_b, &addr_b)
+			&& !pri_cc_cmp_q931_ies(&cc_record->saved_ie_contents, length, q931_ies)) {
 			/* Found the record */
 			break;
 		}
 	}
 
 	return cc_record;
-
-	/* BUGBUG Probably need to add BC, HLC, and LLC comparison as well. */
-	/*! \todo BUGBUG pri_cc_find_by_addressing() not written */
 }
 
 /*!
@@ -1658,6 +1760,12 @@
 {
 	struct pri_cc_record *cc_record;
 
+	if (!PRI_MASTER(ctrl)->cc_support) {
+		/* Call completion is disabled. */
+		send_facility_error(ctrl, call, invoke->invoke_id,
+			ROSE_ERROR_Gen_NotSubscribed);
+		return;
+	}
 	cc_record = pri_cc_find_by_linkage(ctrl,
 		invoke->args.etsi.CCBSRequest.call_linkage_id);
 	if (!cc_record) {
@@ -1685,6 +1793,79 @@
 
 	/* 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);
+}
+
+/*!
+ * \brief Respond to the received PTP CCBS_T_Request/CCNR_T_Request invoke message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which the message came.
+ * \param msgtype Q.931 message type ie is in.
+ * \param invoke Decoded ROSE invoke message contents.
+ *
+ * \return Nothing
+ */
+void pri_cc_ptp_request(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke)
+{
+	struct pri_cc_record *cc_record;
+	struct q931_party_address party_a;
+	struct q931_party_address party_b;
+
+	if (msgtype != Q931_REGISTER) {
+		/* Ignore CC request message since it did not come in on the correct message. */
+		return;
+	}
+	if (!PRI_MASTER(ctrl)->cc_support) {
+		/* Call completion is disabled. */
+		rose_error_msg_encode(ctrl, call, Q931_ANY_MESSAGE, invoke->invoke_id,
+			ROSE_ERROR_Gen_NotSubscribed);
+		call->cc.hangup_call = 1;
+		return;
+	}
+
+	q931_party_address_init(&party_a);
+	rose_copy_address_to_q931(ctrl, &party_a,
+		&invoke->args.etsi.CCBS_T_Request.originating);
+	q931_party_address_init(&party_b);
+	rose_copy_address_to_q931(ctrl, &party_b,
+		&invoke->args.etsi.CCBS_T_Request.destination);
+	cc_record = pri_cc_find_by_addressing(ctrl, &party_a, &party_b,
+		invoke->args.etsi.CCBS_T_Request.q931ie.length,
+		invoke->args.etsi.CCBS_T_Request.q931ie.contents);
+	if (!cc_record || cc_record->state != CC_STATE_AVAILABLE) {
+		/* Could not find the record or already activated */
+		rose_error_msg_encode(ctrl, call, Q931_ANY_MESSAGE, invoke->invoke_id,
+			ROSE_ERROR_CCBS_T_ShortTermDenial);
+		call->cc.hangup_call = 1;
+		return;
+	}
+
+	/*
+	 * We already have the presentationAllowedIndicator in the cc_record
+	 * when we saved the original call information.
+	 */
+
+	/* Determine negotiated service_retention. */
+	cc_record->option.retain_service =
+		(invoke->args.etsi.CCBS_T_Request.retention_supported
+			&& cc_record->master->cc.option.retain_service) ? 1 : 0;
+
+	/* Link the signaling link to the cc_record. */
+	call->cc.record = cc_record;
+	cc_record->signaling = call;
+
+	/* 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_CCNR_T_Request) ? 1 : 0;
+
+	/* Lets keep this signaling link around for awhile. */
+	call->cis_recognized = 1;
 
 	pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST);
 }
@@ -2798,6 +2979,21 @@
 
 /*!
  * \internal
+ * \brief FSM action to set A status as free.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \return Nothing
+ */
+static void pri_cc_act_set_a_status_free(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+	PRI_CC_ACT_DEBUG_OUTPUT(ctrl);
+	cc_record->party_a_status = CC_PARTY_A_AVAILABILITY_FREE;
+}
+
+/*!
+ * \internal
  * \brief FSM action to pass up party A status to upper layer.
  *
  * \param ctrl D channel controller.
@@ -2851,6 +3047,7 @@
 	subcmd->cmd = PRI_SUBCMD_CC_REQ;
 	subcmd->u.cc_request.cc_id =  cc_record->record_id;
 	subcmd->u.cc_request.mode = cc_record->is_ccnr ? 1 /* ccnr */ : 0 /* ccbs */;
+	subcmd->u.cc_request.retain_service = cc_record->option.retain_service;
 }
 
 /*!
@@ -2898,7 +3095,7 @@
 	}
 
 	subcmd->cmd = PRI_SUBCMD_CC_CALL;
-	subcmd->u.cc_call.cc_id =  cc_record->record_id;
+	subcmd->u.cc_call.cc_id = cc_record->record_id;
 }
 
 /*!
@@ -4018,6 +4215,342 @@
 
 /*!
  * \internal
+ * \brief CC FSM PTP agent CC_STATE_IDLE.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ * \param event Event to process.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fsm_ptp_agent_idle(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
+{
+	switch (event) {
+	case CC_EVENT_AVAILABLE:
+		cc_record->state = CC_STATE_PENDING_AVAILABLE;
+		break;
+	case CC_EVENT_CANCEL:
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
+ * \brief CC FSM PTP agent CC_STATE_PENDING_AVAILABLE.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ * \param event Event to process.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fsm_ptp_agent_pend_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
+{
+	switch (event) {
+	case CC_EVENT_MSG_ALERTING:
+		pri_cc_act_send_cc_available(ctrl, call, cc_record, Q931_ALERTING);
+		cc_record->state = CC_STATE_AVAILABLE;
+		break;
+	case CC_EVENT_MSG_DISCONNECT:
+		pri_cc_act_send_cc_available(ctrl, call, cc_record, Q931_DISCONNECT);
+		cc_record->state = CC_STATE_AVAILABLE;
+		break;
+	case CC_EVENT_CANCEL:
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
+ * \brief CC FSM PTP agent CC_STATE_AVAILABLE.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ * \param event Event to process.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fsm_ptp_agent_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
+{
+	/*
+	 * For PTP mode the T_RETENTION timer is not defined.  However,
+	 * we will use it anyway in this state to protect our resources
+	 * from leaks caused by user A not requesting CC.  This timer
+	 * should be set much longer than the PTMP network link to
+	 * allow for variations in user A's CC offer timer.
+	 */
+	switch (event) {
+	case CC_EVENT_MSG_RELEASE:
+	case CC_EVENT_MSG_RELEASE_COMPLETE:
+		pri_cc_act_stop_t_retention(ctrl, cc_record);
+		pri_cc_act_start_t_retention(ctrl, cc_record);
+		break;
+	case CC_EVENT_CC_REQUEST:
+		pri_cc_act_pass_up_cc_request(ctrl, cc_record);
+		pri_cc_act_stop_t_retention(ctrl, cc_record);
+		cc_record->state = CC_STATE_REQUESTED;
+		break;
+	case CC_EVENT_TIMEOUT_T_RETENTION:
+		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
+		pri_cc_act_stop_t_retention(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	case CC_EVENT_CANCEL:
+		pri_cc_act_stop_t_retention(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
+ * \brief CC FSM PTP agent CC_STATE_REQUESTED.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ * \param event Event to process.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fsm_ptp_agent_req(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
+{
+	switch (event) {
+	case CC_EVENT_CC_REQUEST_ACCEPT:
+		/* Start T_CCBS5/T_CCNR5 depending upon CC mode. */
+		pri_cc_act_start_t_supervision(ctrl, cc_record);
+		pri_cc_act_reset_a_status(ctrl, cc_record);
+		cc_record->state = CC_STATE_ACTIVATED;
+		break;
+	case CC_EVENT_SIGNALING_GONE:
+		/* Signaling link cleared. */
+		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	case CC_EVENT_CANCEL:
+		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
+ * \brief CC FSM PTP agent CC_STATE_WAIT_DESTRUCTION.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ * \param event Event to process.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fsm_ptp_agent_wait_destruction(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
+{
+	/*
+	 * Delayed disconnect of the signaling link to allow subcmd events
+	 * from the signaling link to be passed up.
+	 */
+	switch (event) {
+	case CC_EVENT_SIGNALING_GONE:
+		/* Signaling link cleared. */
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	case CC_EVENT_HANGUP_SIGNALING:
+		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	case CC_EVENT_CANCEL:
+		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
+ * \brief CC FSM PTP agent CC_STATE_ACTIVATED.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ * \param event Event to process.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fsm_ptp_agent_activated(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
+{
+	switch (event) {
+	case CC_EVENT_REMOTE_USER_FREE:
+		pri_cc_act_pass_up_a_status(ctrl, cc_record);
+		if (cc_record->party_a_status == CC_PARTY_A_AVAILABILITY_BUSY) {
+			cc_record->state = CC_STATE_SUSPENDED;
+		} else {
+			pri_cc_act_send_remote_user_free(ctrl, cc_record);
+			cc_record->state = CC_STATE_WAIT_CALLBACK;
+		}
+		break;
+	case CC_EVENT_SUSPEND:
+		/* Received CCBS_T_Suspend */
+		pri_cc_act_set_a_status_busy(ctrl, cc_record);
+		break;
+	case CC_EVENT_RESUME:
+		/* Received CCBS_T_Resume */
+		pri_cc_act_reset_a_status(ctrl, cc_record);
+		break;
+	case CC_EVENT_RECALL:
+		/* Received CCBS_T_Call */
+		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
+		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
+		break;
+	case CC_EVENT_TIMEOUT_T_SUPERVISION:
+		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
+		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
+		break;
+	case CC_EVENT_SIGNALING_GONE:
+		/* Signaling link cleared. */
+		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	case CC_EVENT_CANCEL:
+		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
+ * \brief CC FSM PTP agent CC_STATE_WAIT_CALLBACK.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ * \param event Event to process.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fsm_ptp_agent_wait_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
+{
+	switch (event) {
+	case CC_EVENT_SUSPEND:
+		/* Received CCBS_T_Suspend */
+		pri_cc_act_set_a_status_busy(ctrl, cc_record);
+		pri_cc_act_pass_up_a_status(ctrl, cc_record);
+		cc_record->state = CC_STATE_SUSPENDED;
+		break;
+	case CC_EVENT_RECALL:
+		/* Received CCBS_T_Call */
+		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
+		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
+		break;
+	case CC_EVENT_TIMEOUT_T_SUPERVISION:
+		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
+		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
+		break;
+	case CC_EVENT_SIGNALING_GONE:
+		/* Signaling link cleared. */
+		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	case CC_EVENT_CANCEL:
+		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
+ * \brief CC FSM PTP agent CC_STATE_SUSPENDED.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ * \param event Event to process.
+ *
+ * \return Nothing
+ */
+static void pri_cc_fsm_ptp_agent_suspended(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
+{
+	switch (event) {
+	case CC_EVENT_RESUME:
+		/* Received CCBS_T_Resume */
+		pri_cc_act_set_a_status_free(ctrl, cc_record);
+		pri_cc_act_pass_up_a_status(ctrl, cc_record);
+		pri_cc_act_reset_a_status(ctrl, cc_record);
+		cc_record->state = CC_STATE_ACTIVATED;
+		break;
+	case CC_EVENT_RECALL:
+		/* Received CCBS_T_Call */
+		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
+		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
+		break;
+	case CC_EVENT_TIMEOUT_T_SUPERVISION:
+		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
+		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
+		break;
+	case CC_EVENT_SIGNALING_GONE:
+		/* Signaling link cleared. */
+		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	case CC_EVENT_CANCEL:
+		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
+		pri_cc_act_stop_t_supervision(ctrl, cc_record);
+		pri_cc_act_set_self_destruct(ctrl, cc_record);
+		cc_record->state = CC_STATE_IDLE;
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
  * \brief CC FSM PTP monitor CC_STATE_IDLE.
  *
  * \param ctrl D channel controller.
@@ -4378,10 +4911,17 @@
 /* *INDENT-ON* */
 };
 
-/*! \todo BUGBUG pri_cc_fsm_ptp_agent[] not written */
 /*! CC FSM PTMP agent state table. */
 static const pri_cc_fsm_state pri_cc_fsm_ptp_agent[CC_STATE_NUM] = {
 /* *INDENT-OFF* */
+	[CC_STATE_IDLE] = pri_cc_fsm_ptp_agent_idle,
+	[CC_STATE_PENDING_AVAILABLE] = pri_cc_fsm_ptp_agent_pend_avail,
+	[CC_STATE_AVAILABLE] = pri_cc_fsm_ptp_agent_avail,
+	[CC_STATE_REQUESTED] = pri_cc_fsm_ptp_agent_req,
+	[CC_STATE_WAIT_DESTRUCTION] = pri_cc_fsm_ptp_agent_wait_destruction,
+	[CC_STATE_ACTIVATED] = pri_cc_fsm_ptp_agent_activated,
+	[CC_STATE_WAIT_CALLBACK] = pri_cc_fsm_ptp_agent_wait_callback,
+	[CC_STATE_SUSPENDED] = pri_cc_fsm_ptp_agent_suspended,
 /* *INDENT-ON* */
 };
 
@@ -4777,7 +5317,7 @@
  * \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)
+static int pri_cc_req_rsp_ptmp(struct pri *ctrl, struct pri_cc_record *cc_record, int status)
 {
 	int fail;
 
@@ -4828,6 +5368,145 @@
 }
 
 /*!
+ * \internal
+ * \brief Encode a PTP cc-request reply 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_cc_etsi_ptp_req_rsp(struct pri *ctrl, unsigned char *pos,
+	unsigned char *end, struct pri_cc_record *cc_record)
+{
+	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 = cc_record->response.invoke_operation;
+
+	/* CCBS/CCNR reply */
+	msg.args.etsi.CCBS_T_Request.retention_supported = cc_record->option.retain_service;
+
+	pos = rose_encode_result(ctrl, pos, end, &msg);
+
+	return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode and queue PTP a cc-request reply message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_cc_etsi_ptp_req_rsp_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
+{
+	unsigned char buffer[256];
+	unsigned char *end;
+
+	end = enc_cc_etsi_ptp_req_rsp(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 Send the CC activation request result PTMP.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_cc_etsi_ptp_req_rsp(struct pri *ctrl, struct pri_cc_record *cc_record)
+{
+	if (rose_cc_etsi_ptp_req_rsp_encode(ctrl, cc_record->signaling, cc_record)
+		|| q931_facility(ctrl, cc_record->signaling)) {
+		pri_message(ctrl,
+			"Could not schedule facility message for CC request result message.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Response to an incoming CC activation request PTP.
+ *
+ * \param ctrl D channel controller.
+ * \param cc_record Call completion record to process event.
+ * \param status success(0)/timeout(1)/
+ *		short_term_denial(2)/long_term_denial(3)/not_subscribed(4)/queue_full(5)
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int pri_cc_req_rsp_ptp(struct pri *ctrl, struct pri_cc_record *cc_record, int status)
+{
+	int fail;
+
+	switch (cc_record->response.invoke_operation) {
+	case ROSE_ETSI_CCBS_T_Request:
+	case ROSE_ETSI_CCNR_T_Request:
+		break;
+	default:
+		/* We no longer know how to send the response.  Should not happen. */
+		return -1;
+	}
+	if (!cc_record->signaling) {
+		return -1;
+	}
+
+	fail = 0;
+	if (status) {
+		enum rose_error_code code;
+
+		switch (status) {
+		default:
+		case 1:/* timeout */
+		case 5:/* queue_full */
+		case 2:/* short_term_denial */
+			code = ROSE_ERROR_CCBS_T_ShortTermDenial;
+			break;
+		case 3:/* long_term_denial */
+			code = ROSE_ERROR_CCBS_T_LongTermDenial;
+			break;
+		case 4:/* not_subscribed */
+			code = ROSE_ERROR_Gen_NotSubscribed;
+			break;
+		}
+		rose_error_msg_encode(ctrl, cc_record->signaling, Q931_ANY_MESSAGE,
+			cc_record->response.invoke_id, code);
+		pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CANCEL);
+	} else {
+		/* Successful CC activation. */
+		if (send_cc_etsi_ptp_req_rsp(ctrl, cc_record)) {
+			fail = -1;
+		}
+		pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CC_REQUEST_ACCEPT);
+	}
+	return fail;
+}
+
+/*!
  * \brief Response to an incoming CC activation request.
  *
  * \param ctrl D channel controller.
@@ -4868,11 +5547,13 @@
 	case PRI_SWITCH_EUROISDN_E1:
 	case PRI_SWITCH_EUROISDN_T1:
 		if (q931_is_ptmp(ctrl)) {
-			if (!rose_cc_req_rsp_ptmp(ctrl, cc_record, status)) {
+			if (!pri_cc_req_rsp_ptmp(ctrl, cc_record, status)) {
 				fail = 0;
 			}
 		} else {
-			/*! \todo BUGBUG pri_cc_req_rsp(PTP) not written */
+			if (!pri_cc_req_rsp_ptp(ctrl, cc_record, status)) {
+				fail = 0;
+			}
 		}
 		break;
 	default:

Modified: team/group/ccss/pri_facility.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_facility.c?view=diff&rev=1393&r1=1392&r2=1393
==============================================================================
--- team/group/ccss/pri_facility.c (original)
+++ team/group/ccss/pri_facility.c Fri Dec 18 22:42:38 2009
@@ -3507,6 +3507,7 @@
 	struct pri_cc_record *cc_record;
 	struct pri_subcommand *subcmd;
 	struct q931_party_id party_id;
+	struct q931_party_address party_address;
 	struct q931_party_redirecting deflection;
 
 	switch (invoke->operation) {
@@ -3950,7 +3951,7 @@
 		}
 
 		/* Save off data to know how to send back any response. */
-		cc_record->response.signaling = call;
+		//cc_record->response.signaling = call;
 		cc_record->response.invoke_operation = invoke->operation;
 		cc_record->response.invoke_id = invoke->invoke_id;
 
@@ -4013,17 +4014,37 @@
 		subcmd->u.cc_stop_alerting.cc_id = cc_record->record_id;
 		break;
 	case ROSE_ETSI_CCBS_T_Request:
-		/* BUGBUG ROSE_ETSI_CCBS_T_Request */
-		//pri_cc_ptp_request(ctrl, call, msgtype, invoke);
-		call->cc.hangup_call = 1;
+		pri_cc_ptp_request(ctrl, call, msgtype, invoke);
 		break;
 	case ROSE_ETSI_CCNR_T_Request:
-		/* BUGBUG ROSE_ETSI_CCNR_T_Request */
-		//pri_cc_ptp_request(ctrl, call, msgtype, invoke);
-		call->cc.hangup_call = 1;
+		pri_cc_ptp_request(ctrl, call, msgtype, invoke);
 		break;
 	case ROSE_ETSI_CCBS_T_Call:
-		/* BUGBUG ROSE_ETSI_CCBS_T_Call */
+		if (msgtype != Q931_SETUP) {
+			/* Ignore since it did not come in on the correct message. */
+			break;

[... 156 lines stripped ...]



More information about the libpri-commits mailing list