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

SVN commits to the libpri project libpri-commits at lists.digium.com
Fri May 28 13:44:00 CDT 2010


Author: rmudgett
Date: Fri May 28 13:43:57 2010
New Revision: 1746

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1746
Log:
ETSI Call Waiting support.

Add the ability to announce a call to an endpoint when there are no B
channels available.  A call waiting call is a SETUP message with no B
channel selected.

Relevant specification: EN 300 056, EN 300 057, EN 300 058

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

Modified:
    branches/1.4/libpri.h
    branches/1.4/pri.c
    branches/1.4/pri_internal.h
    branches/1.4/pri_q931.h
    branches/1.4/q931.c

Modified: branches/1.4/libpri.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/libpri.h?view=diff&rev=1746&r1=1745&r2=1746
==============================================================================
--- branches/1.4/libpri.h (original)
+++ branches/1.4/libpri.h Fri May 28 13:43:57 2010
@@ -98,6 +98,7 @@
 #define PRI_EVENT_RETRIEVE		24	/* RETRIEVE request received */
 #define PRI_EVENT_RETRIEVE_ACK	25	/* RETRIEVE_ACKNOWLEDGE received */
 #define PRI_EVENT_RETRIEVE_REJ	26	/* RETRIEVE_REJECT received */
+#define PRI_EVENT_CONNECT_ACK	27	/* CONNECT_ACKNOWLEDGE received */
 
 /* Simple states */
 #define PRI_STATE_DOWN		0
@@ -1160,6 +1161,13 @@
 	struct pri_subcommands *subcmds;
 };
 
+struct pri_event_connect_ack {
+	int e;
+	int channel;
+	q931_call *call;
+	struct pri_subcommands *subcmds;
+};
+
 typedef union {
 	int e;
 	pri_event_generic gen;		/* Generic view */
@@ -1184,6 +1192,7 @@
 	struct pri_event_retrieve retrieve;
 	struct pri_event_retrieve_ack retrieve_ack;
 	struct pri_event_retrieve_rej retrieve_rej;
+	struct pri_event_connect_ack connect_ack;
 } pri_event;
 
 struct pri;
@@ -1284,9 +1293,32 @@
    Set non-isdn to non-zero if you are not connecting to ISDN equipment */
 int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn);
 
-/* Answer the call on the given channel (ignored if you called acknowledge already).
+/* Answer(CONNECT) the call on the given channel.
    Set non-isdn to non-zero if you are not connecting to ISDN equipment */
 int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
+
+/*!
+ * \brief Send the manual CONNECT_ACKNOWLEDGE message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param channel Selected channel to assign to the call waiting call.
+ * Zero if do not include the channel id ie in the CONNECT_ACKNOWLEDGE message.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_connect_ack(struct pri *ctrl, q931_call *call, int channel);
+
+/*!
+ * \brief Set the manual CONNECT_ACKNOWLEDGE message enable flag.
+ *
+ * \param ctrl D channel controller.
+ * \param enable TRUE to enable manual CONNECT_ACKNOWLEDGE message feature.
+ *
+ * \return Nothing
+ */
+void pri_connect_ack_enable(struct pri *ctrl, int enable);
 
 /*!
  * \brief Give connected line information to a call

Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=1746&r1=1745&r2=1746
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Fri May 28 13:43:57 2010
@@ -507,6 +507,7 @@
 		{ PRI_EVENT_RETRIEVE,       "Retrieve" },
 		{ PRI_EVENT_RETRIEVE_ACK,   "Retrieve ACK" },
 		{ PRI_EVENT_RETRIEVE_REJ,   "Retrieve Rej" },
+		{ PRI_EVENT_CONNECT_ACK,    "Connect ACK" },
 /* *INDENT-ON* */
 	};
 
@@ -691,6 +692,22 @@
 	if (!pri || !call)
 		return -1;
 	return q931_connect(pri, call, channel, nonisdn);
+}
+
+int pri_connect_ack(struct pri *ctrl, q931_call *call, int channel)
+{
+	if (!ctrl || !call) {
+		return -1;
+	}
+	return q931_connect_acknowledge(ctrl, call, channel);
+}
+
+void pri_connect_ack_enable(struct pri *ctrl, int enable)
+{
+	if (ctrl) {
+		ctrl = PRI_MASTER(ctrl);
+		ctrl->manual_connect_ack = enable ? 1 : 0;
+	}
 }
 
 /*!

Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=1746&r1=1745&r2=1746
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Fri May 28 13:43:57 2010
@@ -108,6 +108,7 @@
 	unsigned int cc_support:1;/* TRUE if upper layer supports call completion. */
 	unsigned int transfer_support:1;/* TRUE if the upper layer supports ECT */
 	unsigned int aoc_support:1;/* TRUE if can send AOC events to the upper layer. */
+	unsigned int manual_connect_ack:1;/* TRUE if the CONNECT_ACKNOWLEDGE is sent with API call */
 
 	/* MDL variables */
 	int mdl_error;

Modified: branches/1.4/pri_q931.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_q931.h?view=diff&rev=1746&r1=1745&r2=1746
==============================================================================
--- branches/1.4/pri_q931.h (original)
+++ branches/1.4/pri_q931.h Fri May 28 13:43:57 2010
@@ -475,6 +475,7 @@
 extern int q931_keypad_facility(struct pri *pri, q931_call *call, const char *digits);
 
 extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn);
+int q931_connect_acknowledge(struct pri *ctrl, q931_call *call, int channel);
 
 extern int q931_release(struct pri *pri, q931_call *call, int cause);
 

Modified: branches/1.4/q931.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q931.c?view=diff&rev=1746&r1=1745&r2=1746
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Fri May 28 13:43:57 2010
@@ -1063,6 +1063,10 @@
 	}
 	if (call->chanflags & FLAG_EXCLUSIVE) {
 		/* Channel is exclusive */
+		if (!(ie->data[pos] & 0x03)) {
+			/* An exclusive no channel id ie is to be discarded. */
+			return 0;
+		}
 		ie->data[pos] |= 0x08;
 	} else if (!call->chanflags) {
 		/* Don't need this IE */
@@ -5179,20 +5183,6 @@
 	return res;
 }
 
-static int connect_acknowledge_ies[] = { -1 };
-
-static int gr303_connect_acknowledge_ies[] = { Q931_CHANNEL_IDENT, -1 };
-
-static int q931_connect_acknowledge(struct pri *ctrl, q931_call *c)
-{
-	if (ctrl->subchannel && !ctrl->bri) {
-		if (ctrl->localtype == PRI_CPE)
-			return send_message(ctrl, c, Q931_CONNECT_ACKNOWLEDGE, gr303_connect_acknowledge_ies);
-	} else
-		return send_message(ctrl, c, Q931_CONNECT_ACKNOWLEDGE, connect_acknowledge_ies);
-	return 0;
-}
-
 /*!
  * \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
  *
@@ -5216,6 +5206,49 @@
 		}
 	}
 	return call;
+}
+
+static int connect_ack_ies[] = { -1 };
+static int connect_ack_w_chan_id_ies[] = { Q931_CHANNEL_IDENT, -1 };
+static int gr303_connect_ack_ies[] = { Q931_CHANNEL_IDENT, -1 };
+
+int q931_connect_acknowledge(struct pri *ctrl, q931_call *call, int channel)
+{
+	int *use_ies;
+	struct q931_call *winner;
+
+	winner = q931_find_winning_call(call);
+	if (!winner) {
+		return -1;
+	}
+
+	if (winner != call) {
+		UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_ACTIVE);
+		call->peercallstate = Q931_CALL_STATE_ACTIVE;
+	}
+	UPDATE_OURCALLSTATE(ctrl, winner, Q931_CALL_STATE_ACTIVE);
+	winner->peercallstate = Q931_CALL_STATE_ACTIVE;
+	if (channel) {
+		winner->ds1no = (channel & 0xff00) >> 8;
+		winner->ds1explicit = (channel & 0x10000) >> 16;
+		winner->channelno = channel & 0xff;
+		winner->chanflags &= ~FLAG_PREFERRED;
+		winner->chanflags |= FLAG_EXCLUSIVE;
+	}
+	use_ies = NULL;
+	if (ctrl->subchannel && !ctrl->bri) {
+		if (ctrl->localtype == PRI_CPE) {
+			use_ies = gr303_connect_ack_ies;
+		}
+	} else if (channel) {
+		use_ies = connect_ack_w_chan_id_ies;
+	} else {
+		use_ies = connect_ack_ies;
+	}
+	if (use_ies) {
+		return send_message(ctrl, winner, Q931_CONNECT_ACKNOWLEDGE, use_ies);
+	}
+	return 0;
 }
 
 /*!
@@ -5693,6 +5726,8 @@
 			release_compl = 1;
 			break;
 		}
+		/* Fall through */
+	case PRI_CAUSE_INCOMPATIBLE_DESTINATION:
 		/* See Q.931 Section 5.3.2 a) */
 		switch (c->ourcallstate) {
 		case Q931_CALL_STATE_NULL:
@@ -5704,6 +5739,13 @@
 			 */
 			disconnect = 0;
 			release_compl = 1;
+			break;
+		case Q931_CALL_STATE_CONNECT_REQUEST:
+			/*
+			 * Send RELEASE because the B channel negotiation failed
+			 * for call waiting.
+			 */
+			disconnect = 0;
 			break;
 		default:
 			/*
@@ -7291,8 +7333,6 @@
 			q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE);
 			break;
 		}
-		UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
-		c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
 
 		ctrl->ev.e = PRI_EVENT_ANSWER;
 		ctrl->ev.answer.subcmds = &ctrl->subcmds;
@@ -7304,7 +7344,12 @@
 		libpri_copy_string(ctrl->ev.answer.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.answer.useruserinfo));
 		c->useruserinfo[0] = '\0';
 
-		q931_connect_acknowledge(ctrl, c);
+		if (!PRI_MASTER(ctrl)->manual_connect_ack) {
+			q931_connect_acknowledge(ctrl, c, 0);
+		} else {
+			UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CONNECT_REQUEST);
+			c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
+		}
 
 		if (c->cis_auto_disconnect && c->cis_call) {
 			/* Make sure WE release when we initiate a signalling only connection */
@@ -7390,14 +7435,26 @@
 			q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
 			break;
 		}
-		if (!(c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) &&
-		    !(c->ourcallstate == Q931_CALL_STATE_ACTIVE &&
-		      (ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG))) {
-			q931_status(ctrl,c,PRI_CAUSE_WRONG_MESSAGE);
-			break;
-		}
-		UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
-		c->peercallstate = Q931_CALL_STATE_ACTIVE;
+		switch (c->ourcallstate) {
+		default:
+			if (ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG) {
+				q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE);
+				break;
+			}
+			/* Fall through */
+		case Q931_CALL_STATE_CONNECT_REQUEST:
+		case Q931_CALL_STATE_ACTIVE:
+			UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
+			c->peercallstate = Q931_CALL_STATE_ACTIVE;
+			if (PRI_MASTER(ctrl)->manual_connect_ack) {
+				ctrl->ev.e = PRI_EVENT_CONNECT_ACK;
+				ctrl->ev.connect_ack.subcmds = &ctrl->subcmds;
+				ctrl->ev.connect_ack.channel = q931_encode_channel(c);
+				ctrl->ev.connect_ack.call = c->master_call;
+				return Q931_RES_HAVEEVENT;
+			}
+			break;
+		}
 		break;
 	case Q931_STATUS:
 		if (missingmand) {




More information about the libpri-commits mailing list