[libpri-commits] rmudgett: branch 1.4 r2172 - /branches/1.4/

SVN commits to the libpri project libpri-commits at lists.digium.com
Tue Dec 21 16:49:35 UTC 2010


Author: rmudgett
Date: Tue Dec 21 10:49:30 2010
New Revision: 2172

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=2172
Log:
Add call transfer exchange of subaddresses support and fix PTMP call transfer signaling.

* Add the ability to exchange subaddresses for ETSI PTMP, ETSI PTP, and
Q.SIG for call transfer.

* Fix ETSI PTMP to send the correct messages depending on the call state
for call transfer.  NOTE: Some ISDN phones only handle the NOTIFY message
that the EN 300-369 spec says should be sent only if the call has not
connected yet.

JIRA LIBPRI-47
JIRA SWP-2363

Review:	https://reviewboard.asterisk.org/r/1051/

Modified:
    branches/1.4/pri.c
    branches/1.4/pri_facility.c
    branches/1.4/pri_facility.h
    branches/1.4/pri_internal.h
    branches/1.4/q931.c

Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=2172&r1=2171&r2=2172
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Tue Dec 21 10:49:30 2010
@@ -949,6 +949,9 @@
 {
 	struct q931_party_id party_id;
 	unsigned idx;
+	unsigned new_name;
+	unsigned new_number;
+	unsigned new_subaddress;
 	struct q931_call *subcall;
 
 	if (!ctrl || !pri_is_call_valid(ctrl, call)) {
@@ -957,13 +960,14 @@
 
 	pri_copy_party_id_to_q931(&party_id, &connected->id);
 	q931_party_id_fixup(ctrl, &party_id);
-	if (!q931_party_id_cmp(&party_id, &call->local_id)) {
-		/* The local party information did not change so do nothing. */
-		return 0;
-	}
+
+	new_name = q931_party_name_cmp(&party_id.name, &call->local_id.name);
+	new_number = q931_party_number_cmp(&party_id.number, &call->local_id.number);
+	new_subaddress = party_id.subaddress.valid
+		&& q931_party_subaddress_cmp(&party_id.subaddress, &call->local_id.subaddress);
+
+	/* Update the call and all subcalls with new local_id. */
 	call->local_id = party_id;
-
-	/* Update all subcalls with new local_id. */
 	if (call->outboundbroadcast && call->master_call == call) {
 		for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) {
 			subcall = call->subcalls[idx];
@@ -982,23 +986,100 @@
 		 * The local party transferred to someone else before
 		 * the remote end answered.
 		 */
+		switch (ctrl->switchtype) {
+		case PRI_SWITCH_EUROISDN_E1:
+		case PRI_SWITCH_EUROISDN_T1:
+			if (BRI_NT_PTMP(ctrl)) {
+				/*
+				 * NT PTMP mode
+				 *
+				 * We should not send these messages to the network if we are
+				 * the CPE side since phones do not transfer calls within
+				 * themselves.  Well... If you consider handing the handset to
+				 * someone else a transfer then how is the network to know?
+				 */
+				if (new_number) {
+					q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
+						&party_id.number);
+				}
+				if (new_subaddress || (party_id.subaddress.valid && new_number)) {
+					q931_subaddress_transfer(ctrl, call);
+				}
+			} else if (PTP_MODE(ctrl)) {
+				/* PTP mode */
+				if (new_number) {
+					/* Immediately send EctInform APDU, callStatus=answered(0) */
+					send_call_transfer_complete(ctrl, call, 0);
+				}
+				if (new_subaddress || (party_id.subaddress.valid && new_number)) {
+					q931_subaddress_transfer(ctrl, call);
+				}
+			}
+			break;
+		case PRI_SWITCH_QSIG:
+			if (new_name || new_number) {
+				/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
+				send_call_transfer_complete(ctrl, call, 0);
+			}
+			if (new_subaddress
+				|| (party_id.subaddress.valid && (new_name || new_number))) {
+				q931_subaddress_transfer(ctrl, call);
+			}
+			break;
+		default:
+			break;
+		}
+		break;
 	case Q931_CALL_STATE_ACTIVE:
 		switch (ctrl->switchtype) {
 		case PRI_SWITCH_EUROISDN_E1:
 		case PRI_SWITCH_EUROISDN_T1:
-			if (PTMP_MODE(ctrl)) {
-				/* PTMP mode */
-				q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
-					&call->local_id.number);
-			} else {
+			if (BRI_NT_PTMP(ctrl)) {
+				/*
+				 * NT PTMP mode
+				 *
+				 * We should not send these messages to the network if we are
+				 * the CPE side since phones do not transfer calls within
+				 * themselves.  Well... If you consider handing the handset to
+				 * someone else a transfer then how is the network to know?
+				 */
+				if (new_number) {
+#if defined(USE_NOTIFY_FOR_ECT)
+					/*
+					 * Some ISDN phones only handle the NOTIFY message that the
+					 * EN 300-369 spec says should be sent only if the call has not
+					 * connected yet.
+					 */
+					q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
+						&party_id.number);
+#else
+					q931_request_subaddress(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
+						&party_id.number);
+#endif	/* defined(USE_NOTIFY_FOR_ECT) */
+				}
+				if (new_subaddress || (party_id.subaddress.valid && new_number)) {
+					q931_subaddress_transfer(ctrl, call);
+				}
+			} else if (PTP_MODE(ctrl)) {
 				/* PTP mode */
-				/* Immediately send EctInform APDU, callStatus=answered(0) */
-				send_call_transfer_complete(ctrl, call, 0);
+				if (new_number) {
+					/* Immediately send EctInform APDU, callStatus=answered(0) */
+					send_call_transfer_complete(ctrl, call, 0);
+				}
+				if (new_subaddress || (party_id.subaddress.valid && new_number)) {
+					q931_subaddress_transfer(ctrl, call);
+				}
 			}
 			break;
 		case PRI_SWITCH_QSIG:
-			/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
-			send_call_transfer_complete(ctrl, call, 0);
+			if (new_name || new_number) {
+				/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
+				send_call_transfer_complete(ctrl, call, 0);
+			}
+			if (new_subaddress
+				|| (party_id.subaddress.valid && (new_name || new_number))) {
+				q931_subaddress_transfer(ctrl, call);
+			}
 			break;
 		default:
 			break;

Modified: branches/1.4/pri_facility.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_facility.c?view=diff&rev=2172&r1=2171&r2=2172
==============================================================================
--- branches/1.4/pri_facility.c (original)
+++ branches/1.4/pri_facility.c Tue Dec 21 10:49:30 2010
@@ -3363,6 +3363,286 @@
 	}
 
 	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Encode the ETSI RequestSubaddress invoke message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param pos Starting position to encode the facility ie contents.
+ * \param end End of facility ie contents encoding data buffer.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_request_subaddress(struct pri *ctrl, unsigned char *pos,
+	unsigned char *end)
+{
+	struct rose_msg_invoke msg;
+
+	pos = facility_encode_header(ctrl, pos, end, NULL);
+	if (!pos) {
+		return NULL;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.operation = ROSE_ETSI_RequestSubaddress;
+	msg.invoke_id = get_invokeid(ctrl);
+
+	pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+	return pos;
+}
+
+/*!
+ * \brief Encode and queue the RequestSubaddress invoke message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode message.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int rose_request_subaddress_encode(struct pri *ctrl, struct q931_call *call)
+{
+	unsigned char buffer[256];
+	unsigned char *end;
+
+	switch (ctrl->switchtype) {
+	case PRI_SWITCH_EUROISDN_E1:
+	case PRI_SWITCH_EUROISDN_T1:
+		end = enc_etsi_request_subaddress(ctrl, buffer, buffer + sizeof(buffer));
+		break;
+	case PRI_SWITCH_QSIG:
+	default:
+		return -1;
+	}
+	if (!end) {
+		return -1;
+	}
+
+	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+}
+
+/*!
+ * \internal
+ * \brief Encode the ETSI SubaddressTransfer invoke message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param pos Starting position to encode the facility ie contents.
+ * \param end End of facility ie contents encoding data buffer.
+ * \param call Call leg from which to encode message.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_subaddress_transfer(struct pri *ctrl, unsigned char *pos,
+	unsigned char *end, struct q931_call *call)
+{
+	struct rose_msg_invoke msg;
+
+	pos = facility_encode_header(ctrl, pos, end, NULL);
+	if (!pos) {
+		return NULL;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.operation = ROSE_ETSI_SubaddressTransfer;
+	msg.invoke_id = get_invokeid(ctrl);
+
+	if (!call->local_id.subaddress.valid) {
+		return NULL;
+	}
+	q931_copy_subaddress_to_rose(ctrl, &msg.args.etsi.SubaddressTransfer.subaddress,
+		&call->local_id.subaddress);
+
+	pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+	return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode the Q.SIG SubaddressTransfer invoke message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param pos Starting position to encode the facility ie contents.
+ * \param end End of facility ie contents encoding data buffer.
+ * \param call Call leg from which to encode message.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_qsig_subaddress_transfer(struct pri *ctrl,
+	unsigned char *pos, unsigned char *end, struct q931_call *call)
+{
+	struct fac_extension_header header;
+	struct rose_msg_invoke msg;
+
+	memset(&header, 0, sizeof(header));
+	header.nfe_present = 1;
+	header.nfe.source_entity = 0;	/* endPINX */
+	header.nfe.destination_entity = 0;	/* endPINX */
+	header.interpretation_present = 1;
+	header.interpretation = 0;	/* discardAnyUnrecognisedInvokePdu */
+	pos = facility_encode_header(ctrl, pos, end, &header);
+	if (!pos) {
+		return NULL;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.operation = ROSE_QSIG_SubaddressTransfer;
+	msg.invoke_id = get_invokeid(ctrl);
+
+	if (!call->local_id.subaddress.valid) {
+		return NULL;
+	}
+	q931_copy_subaddress_to_rose(ctrl,
+		&msg.args.qsig.SubaddressTransfer.redirection_subaddress,
+		&call->local_id.subaddress);
+
+	pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+	return pos;
+}
+
+/*!
+ * \internal
+ * \brief Encode and queue the SubaddressTransfer invoke message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call Call leg from which to encode message.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int rose_subaddress_transfer_encode(struct pri *ctrl, struct q931_call *call)
+{
+	unsigned char buffer[256];
+	unsigned char *end;
+
+	switch (ctrl->switchtype) {
+	case PRI_SWITCH_EUROISDN_E1:
+	case PRI_SWITCH_EUROISDN_T1:
+		end =
+			enc_etsi_subaddress_transfer(ctrl, buffer, buffer + sizeof(buffer), call);
+		break;
+	case PRI_SWITCH_QSIG:
+		end =
+			enc_qsig_subaddress_transfer(ctrl, buffer, buffer + sizeof(buffer), call);
+		break;
+	default:
+		return -1;
+	}
+	if (!end) {
+		return -1;
+	}
+
+	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+}
+
+/*!
+ * \brief Send a FACILITY SubaddressTransfer.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int send_subaddress_transfer(struct pri *ctrl, struct q931_call *call)
+{
+	if (rose_subaddress_transfer_encode(ctrl, call)
+		|| q931_facility(ctrl, call)) {
+		pri_message(ctrl,
+			"Could not schedule facility message for subaddress transfer.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Handle the received RequestSubaddress facility.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \return Nothing
+ */
+static void etsi_request_subaddress(struct pri *ctrl, struct q931_call *call)
+{
+	int changed = 0;
+
+	switch (call->notify) {
+	case PRI_NOTIFY_TRANSFER_ACTIVE:
+		if (q931_party_number_cmp(&call->remote_id.number, &call->redirection_number)) {
+			/* The remote party number information changed. */
+			call->remote_id.number = call->redirection_number;
+			changed = 1;
+		}
+		/* Fall through */
+	case PRI_NOTIFY_TRANSFER_ALERTING:
+		if (call->redirection_number.valid
+			&& q931_party_number_cmp(&call->remote_id.number, &call->redirection_number)) {
+			/* The remote party number information changed. */
+			call->remote_id.number = call->redirection_number;
+			changed = 1;
+		}
+		if (call->remote_id.subaddress.valid) {
+			/*
+			 * Clear the subaddress as the remote party has been changed.
+			 * Any new subaddress will arrive later.
+			 */
+			q931_party_subaddress_init(&call->remote_id.subaddress);
+			changed = 1;
+		}
+		if (changed) {
+			call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* Send our subaddress back if we have one. */
+	if (call->local_id.subaddress.valid) {
+		send_subaddress_transfer(ctrl, call);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Handle the received SubaddressTransfer facility subaddress.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param subaddr Received subaddress of remote party.
+ *
+ * \return Nothing
+ */
+static void handle_subaddress_transfer(struct pri *ctrl, struct q931_call *call, const struct rosePartySubaddress *subaddr)
+{
+	int changed = 0;
+	struct q931_party_subaddress q931_subaddress;
+
+	q931_party_subaddress_init(&q931_subaddress);
+	rose_copy_subaddress_to_q931(ctrl, &q931_subaddress, subaddr);
+	if (q931_party_subaddress_cmp(&call->remote_id.subaddress, &q931_subaddress)) {
+		call->remote_id.subaddress = q931_subaddress;
+		changed = 1;
+	}
+	if (call->redirection_number.valid
+		&& q931_party_number_cmp(&call->remote_id.number, &call->redirection_number)) {
+		/* The remote party number information changed. */
+		call->remote_id.number = call->redirection_number;
+		changed = 1;
+	}
+	if (changed) {
+		call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
+	}
 }
 
 /*!
@@ -4382,12 +4662,12 @@
 		}
 		break;
 	case ROSE_ETSI_RequestSubaddress:
-		/* Ignore since we are not handling subaddresses yet. */
-		break;
-#if 0	/* Not handled yet */
+		etsi_request_subaddress(ctrl, call);
+		break;
 	case ROSE_ETSI_SubaddressTransfer:
-		break;
-#endif	/* Not handled yet */
+		handle_subaddress_transfer(ctrl, call,
+			&invoke->args.etsi.SubaddressTransfer.subaddress);
+		break;
 	case ROSE_ETSI_EctLinkIdRequest:
 		if (!ctrl->transfer_support) {
 			send_facility_error(ctrl, call, invoke->invoke_id,
@@ -4409,11 +4689,23 @@
 			rose_copy_presented_number_unscreened_to_q931(ctrl,
 				&call->remote_id.number, &invoke->args.etsi.EctInform.redirection);
 		}
+
+		/*
+		 * Clear the subaddress as the remote party has been changed.
+		 * Any new subaddress will arrive later.
+		 */
+		q931_party_subaddress_init(&call->remote_id.subaddress);
+
 		if (!invoke->args.etsi.EctInform.status) {
 			/* The remote party for the transfer has not answered yet. */
 			call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE;
 		} else {
 			call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
+		}
+
+		/* Send our subaddress back if we have one. */
+		if (call->local_id.subaddress.valid) {
+			send_subaddress_transfer(ctrl, call);
 		}
 		break;
 	case ROSE_ETSI_EctLoopTest:
@@ -4826,11 +5118,22 @@
 				&invoke->args.qsig.CallTransferComplete.redirection_name);
 		}
 
+		/*
+		 * Clear the subaddress as the remote party has been changed.
+		 * Any new subaddress will arrive later.
+		 */
+		q931_party_subaddress_init(&call->remote_id.subaddress);
+
 		if (invoke->args.qsig.CallTransferComplete.call_status == 1) {
 			/* The remote party for the transfer has not answered yet. */
 			call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE;
 		} else {
 			call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
+		}
+
+		/* Send our subaddress back if we have one. */
+		if (call->local_id.subaddress.valid) {
+			send_subaddress_transfer(ctrl, call);
 		}
 		break;
 	case ROSE_QSIG_CallTransferUpdate:
@@ -4858,10 +5161,10 @@
 			}
 		}
 		break;
-#if 0	/* Not handled yet */
 	case ROSE_QSIG_SubaddressTransfer:
-		break;
-#endif	/* Not handled yet */
+		handle_subaddress_transfer(ctrl, call,
+			&invoke->args.qsig.SubaddressTransfer.redirection_subaddress);
+		break;
 	case ROSE_QSIG_PathReplacement:
 		anfpr_pathreplacement_respond(ctrl, call, ie);
 		break;

Modified: branches/1.4/pri_facility.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_facility.h?view=diff&rev=2172&r1=2171&r2=2172
==============================================================================
--- branches/1.4/pri_facility.h (original)
+++ branches/1.4/pri_facility.h Tue Dec 21 10:49:30 2010
@@ -221,6 +221,8 @@
 int send_reroute_request(struct pri *ctrl, q931_call *call, const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, int subscription_option);
 
 int send_call_transfer_complete(struct pri *pri, q931_call *call, int call_status);
+int rose_request_subaddress_encode(struct pri *ctrl, struct q931_call *call);
+int send_subaddress_transfer(struct pri *ctrl, struct q931_call *call);
 
 int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call);
 int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype);

Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=2172&r1=2171&r2=2172
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Tue Dec 21 10:49:30 2010
@@ -950,6 +950,8 @@
 struct q931_call *q931_find_link_id_call(struct pri *ctrl, int link_id);
 struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call);
 
+int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_number *number);
+int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call);
 int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
 
 struct pri_cc_record *pri_cc_find_by_reference(struct pri *ctrl, unsigned reference_id);

Modified: branches/1.4/q931.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q931.c?view=diff&rev=2172&r1=2171&r2=2172
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Tue Dec 21 10:49:30 2010
@@ -933,6 +933,31 @@
 	}
 
 	return number_value | number_screening;
+}
+
+/*!
+ * \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
+ *
+ * \param call Starting Q.931 call record of search.
+ *
+ * \retval winning-call or given call if not outboundbroadcast.
+ * \retval NULL if no winning call yet.
+ */
+struct q931_call *q931_find_winning_call(struct q931_call *call)
+{
+	struct q931_call *master;
+
+	master = call->master_call;
+	if (master->outboundbroadcast) {
+		/* We have potential subcalls.  Now get the winning call if declared yet. */
+		if (master->pri_winner < 0) {
+			/* Winner not declared yet.*/
+			call = NULL;
+		} else {
+			call = master->subcalls[master->pri_winner];
+		}
+	}
+	return call;
 }
 
 /*!
@@ -4733,6 +4758,88 @@
 	return send_message(ctrl, c, Q931_FACILITY, facility_ies);
 }
 
+static int facility_notify_ies[] = {
+	Q931_IE_FACILITY,
+	Q931_IE_NOTIFY_IND,
+	Q931_IE_REDIRECTION_NUMBER,
+	-1
+};
+
+/*!
+ * \brief Send a FACILITY RequestSubaddress with optional redirection number.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param notify Notification indicator
+ * \param number Redirection number to send if not NULL.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_number *number)
+{
+	struct q931_call *winner;
+
+	winner = q931_find_winning_call(call);
+	if (!winner) {
+		return -1;
+	}
+	if (number) {
+		winner->redirection_number = *number;
+	} else {
+		q931_party_number_init(&winner->redirection_number);
+	}
+	winner->notify = notify;
+	if (rose_request_subaddress_encode(ctrl, winner)
+		|| send_message(ctrl, winner, Q931_FACILITY, facility_notify_ies)) {
+		pri_message(ctrl,
+			"Could not schedule facility message for request subaddress.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief Send a FACILITY SubaddressTransfer to all parties.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call)
+{
+	int status;
+	unsigned idx;
+	struct q931_call *subcall;
+
+	if (call->outboundbroadcast && call->master_call == call) {
+		status = 0;
+		for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) {
+			subcall = call->subcalls[idx];
+			if (subcall) {
+				/* Send to all subcalls that have given a positive response. */
+				switch (subcall->ourcallstate) {
+				case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+				case Q931_CALL_STATE_CALL_DELIVERED:
+				case Q931_CALL_STATE_ACTIVE:
+					if (send_subaddress_transfer(ctrl, subcall)) {
+						status = -1;
+					}
+					break;
+				default:
+					break;
+				}
+			}
+		}
+	} else {
+		status = send_subaddress_transfer(ctrl, call);
+	}
+	return status;
+}
+
 static int notify_ies[] = { Q931_IE_NOTIFY_IND, Q931_IE_REDIRECTION_NUMBER, -1 };
 
 /*!
@@ -5491,31 +5598,6 @@
 	/* release the structure */
 	res += pri_hangup(ctrl, c, cause);
 	return res;
-}
-
-/*!
- * \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
- *
- * \param call Starting Q.931 call record of search.
- *
- * \retval winning-call or given call if not outboundbroadcast.
- * \retval NULL if no winning call yet.
- */
-struct q931_call *q931_find_winning_call(struct q931_call *call)
-{
-	struct q931_call *master;
-
-	master = call->master_call;
-	if (master->outboundbroadcast) {
-		/* We have potential subcalls.  Now get the winning call if declared yet. */
-		if (master->pri_winner < 0) {
-			/* Winner not declared yet.*/
-			call = NULL;
-		} else {
-			call = master->subcalls[master->pri_winner];
-		}
-	}
-	return call;
 }
 
 static int connect_ack_ies[] = { -1 };
@@ -6312,6 +6394,8 @@
 		c->ri = -1;
 		break;
 	case Q931_FACILITY:
+		c->notify = -1;
+		q931_party_number_init(&c->redirection_number);
 		if (q931_is_dummy_call(c)) {
 			q931_party_address_init(&c->called);
 		}
@@ -6412,6 +6496,7 @@
 	case Q931_SETUP_ACKNOWLEDGE:
 		break;
 	case Q931_NOTIFY:
+		c->notify = -1;
 		q931_party_number_init(&c->redirection_number);
 		break;
 	case Q931_HOLD:
@@ -7551,6 +7636,7 @@
 static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand)
 {
 	int res;
+	int changed;
 	struct apdu_event *cur = NULL;
 	struct pri_subcommand *subcmd;
 	struct q931_call *master_call;
@@ -8127,6 +8213,7 @@
 		return Q931_RES_HAVEEVENT;
 	case Q931_NOTIFY:
 		res = 0;
+		changed = 0;
 		switch (c->notify) {
 		case PRI_NOTIFY_CALL_DIVERTING:
 			if (c->redirection_number.valid) {
@@ -8159,13 +8246,29 @@
 				res = Q931_RES_HAVEEVENT;
 			}
 			break;
+		case PRI_NOTIFY_TRANSFER_ACTIVE:
+			if (q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) {
+				/* The remote party number information changed. */
+				c->remote_id.number = c->redirection_number;
+				changed = 1;
+			}
+			/* Fall through */
 		case PRI_NOTIFY_TRANSFER_ALERTING:
-		case PRI_NOTIFY_TRANSFER_ACTIVE:
 			if (c->redirection_number.valid
 				&& q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) {
-				/* The remote party information changed. */
+				/* The remote party number information changed. */
 				c->remote_id.number = c->redirection_number;
-
+				changed = 1;
+			}
+			if (c->remote_id.subaddress.valid) {
+				/*
+				 * Clear the subaddress as the remote party has been changed.
+				 * Any new subaddress will arrive later.
+				 */
+				q931_party_subaddress_init(&c->remote_id.subaddress);
+				changed = 1;
+			}
+			if (changed) {
 				/* Setup connected line subcommand */
 				subcmd = q931_alloc_subcommand(ctrl);
 				if (subcmd) {




More information about the libpri-commits mailing list