[asterisk-commits] rmudgett: branch certified-1.8.15 r407732 - in /certified/branches/1.8.15: ./...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Feb 7 13:01:06 CST 2014


Author: rmudgett
Date: Fri Feb  7 13:01:01 2014
New Revision: 407732

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=407732
Log:
chan_iax2: Block unnecessary control frames to/from the wire.

Establishing an IAX2 call between Asterisk v1.4 and v1.8 (or later)
results in an unexpected call disconnect.  The problem happens because
newer values in the enum ast_control_frame_type are not consistent between
the branch versions of Asterisk.

For example:
1) v1.4 calls v1.8 (or later) using IAX2

2) v1.8 answers and sends a connected line update control frame.  (on v1.8
AST_CONTROL_CONNECTED_LINE = 22)

3) v1.4 receives the control frame as an end-of-q (on v1.4
AST_CONTROL_END_OF_Q = 22)

4) v1.4 disconnects the call once the receive queue becomes empty.

Several things are done by this patch to fix the problem and attempt to
prevent it from happening again in the future:

* Added a warning at the definition of enum ast_control_frame_type about
how to add new control frame values.

* Made block sending and receiving control frames that have no reason to
go over the wire.

* Extended the connectedline iax.conf parameter to also include the
redirecting information updates.

* Updated the connectedline iax.conf parameter documentation to include a
notice that the parameter must be "no" when the peer is an Asterisk v1.4
instance.

(closes issue AST-1302)

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

Merged revisions 407678 from http://svn.asterisk.org/svn/asterisk/branches/1.8

Modified:
    certified/branches/1.8.15/   (props changed)
    certified/branches/1.8.15/channels/chan_iax2.c
    certified/branches/1.8.15/configs/iax.conf.sample
    certified/branches/1.8.15/include/asterisk/frame.h

Propchange: certified/branches/1.8.15/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Modified: certified/branches/1.8.15/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/certified/branches/1.8.15/channels/chan_iax2.c?view=diff&rev=407732&r1=407731&r2=407732
==============================================================================
--- certified/branches/1.8.15/channels/chan_iax2.c (original)
+++ certified/branches/1.8.15/channels/chan_iax2.c Fri Feb  7 13:01:01 2014
@@ -1273,6 +1273,91 @@
 	}
 }
 
+/*!
+ * \internal
+ * \brief Check if a control subtype is allowed on the wire.
+ *
+ * \param subtype Control frame subtype to check if allowed to/from the wire.
+ *
+ * \retval non-zero if allowed.
+ */
+static int iax2_is_control_frame_allowed(int subtype)
+{
+	enum ast_control_frame_type control = subtype;
+	int is_allowed;
+
+	/*
+	 * Note: If we compare the enumeration type, which does not have any
+	 * negative constants, the compiler may optimize this code away.
+	 * Therefore, we must perform an integer comparison here.
+	 */
+	if (subtype == -1) {
+		return -1;
+	}
+
+	/* Default to not allowing control frames to pass. */
+	is_allowed = 0;
+
+	/*
+	 * The switch default is not present in order to take advantage
+	 * of the compiler complaining of a missing enum case.
+	 */
+	switch (control) {
+	/*
+	 * These control frames make sense to send/receive across the link.
+	 */
+	case AST_CONTROL_HANGUP:
+	case AST_CONTROL_RING:
+	case AST_CONTROL_RINGING:
+	case AST_CONTROL_ANSWER:
+	case AST_CONTROL_BUSY:
+	case AST_CONTROL_TAKEOFFHOOK:
+	case AST_CONTROL_OFFHOOK:
+	case AST_CONTROL_CONGESTION:
+	case AST_CONTROL_FLASH:
+	case AST_CONTROL_WINK:
+	case AST_CONTROL_OPTION:
+	case AST_CONTROL_RADIO_KEY:
+	case AST_CONTROL_RADIO_UNKEY:
+	case AST_CONTROL_PROGRESS:
+	case AST_CONTROL_PROCEEDING:
+	case AST_CONTROL_HOLD:
+	case AST_CONTROL_UNHOLD:
+	case AST_CONTROL_VIDUPDATE:
+	case AST_CONTROL_CONNECTED_LINE:
+	case AST_CONTROL_REDIRECTING:
+	case AST_CONTROL_T38_PARAMETERS:
+	case AST_CONTROL_AOC:
+	case AST_CONTROL_INCOMPLETE:
+		is_allowed = -1;
+		break;
+
+	/*
+	 * These control frames do not make sense to send/receive across the link.
+	 */
+	case _XXX_AST_CONTROL_T38:
+		/* The control value is deprecated in favor of AST_CONTROL_T38_PARAMETERS. */
+	case AST_CONTROL_SRCUPDATE:
+		/* Across an IAX link the source is still the same. */
+	case AST_CONTROL_TRANSFER:
+		/* A success/fail status report from calling ast_transfer() on this machine. */
+	case AST_CONTROL_CC:
+		/* The payload contains pointers that are valid for the sending machine only. */
+	case AST_CONTROL_SRCCHANGE:
+		/* Across an IAX link the source is still the same. */
+	case AST_CONTROL_READ_ACTION:
+		/* The action can only be done by the sending machine. */
+	case AST_CONTROL_END_OF_Q:
+		/* This frame would cause the call to unexpectedly hangup. */
+	case AST_CONTROL_UPDATE_RTP_PEER:
+		/* Only meaningful across a bridge on this machine for direct-media exchange. */
+	case AST_CONTROL_CUSTOM:
+		/* By definition custom control frames cannot go across the link. */
+		break;
+	}
+	return is_allowed;
+}
+
 static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
 	/* The MWI subscriptions exist just so the core knows we care about those
@@ -5672,8 +5757,13 @@
 		}
 		break;
 	case AST_CONTROL_CONNECTED_LINE:
-		if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE))
+	case AST_CONTROL_REDIRECTING:
+		if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE)) {
+			/* We are not configured to allow sending these updates. */
+			ast_debug(2, "Callno %u: Config blocked sending control frame %d.\n",
+				callno, condition);
 			goto done;
+		}
 		break;
 	}
 
@@ -7503,6 +7593,12 @@
 
 static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
+	if (type == AST_FRAME_CONTROL && !iax2_is_control_frame_allowed(command)) {
+		/* Control frame should not go out on the wire. */
+		ast_debug(2, "Callno %u: Blocked sending control frame %d.\n",
+			i->callno, command);
+		return 0;
+	}
 	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
 }
 
@@ -10411,13 +10507,6 @@
 			if (f.subclass.codec != iaxs[fr->callno]->videoformat) {
 				ast_debug(1, "Ooh, video format changed to %s\n", ast_getformatname(f.subclass.codec & ~0x1LL));
 				iaxs[fr->callno]->videoformat = f.subclass.codec & ~0x1LL;
-			}
-		}
-		if (f.frametype == AST_FRAME_CONTROL && iaxs[fr->callno]->owner) {
-			if (f.subclass.integer == AST_CONTROL_BUSY) {
-				iaxs[fr->callno]->owner->hangupcause = AST_CAUSE_BUSY;
-			} else if (f.subclass.integer == AST_CONTROL_CONGESTION) {
-				iaxs[fr->callno]->owner->hangupcause = AST_CAUSE_CONGESTION;
 			}
 		}
 		if (f.frametype == AST_FRAME_IAX) {
@@ -11582,17 +11671,48 @@
 		ast_mutex_unlock(&iaxsl[fr->callno]);
 		return 1;
 	}
-	/* Don't allow connected line updates unless we are configured to */
-	if (f.frametype == AST_FRAME_CONTROL && f.subclass.integer == AST_CONTROL_CONNECTED_LINE) {
-		struct ast_party_connected_line connected;
-
-		if (!ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) {
+
+	if (f.frametype == AST_FRAME_CONTROL) {
+		if (!iax2_is_control_frame_allowed(f.subclass.integer)) {
+			/* Control frame not allowed to come from the wire. */
+			ast_debug(2, "Callno %u: Blocked receiving control frame %d.\n",
+				fr->callno, f.subclass.integer);
 			ast_variables_destroy(ies.vars);
 			ast_mutex_unlock(&iaxsl[fr->callno]);
 			return 1;
 		}
-
-		/* Initialize defaults */
+		if (f.subclass.integer == AST_CONTROL_CONNECTED_LINE
+			|| f.subclass.integer == AST_CONTROL_REDIRECTING) {
+			if (!ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) {
+				/* We are not configured to allow receiving these updates. */
+				ast_debug(2, "Callno %u: Config blocked receiving control frame %d.\n",
+					fr->callno, f.subclass.integer);
+				ast_variables_destroy(ies.vars);
+				ast_mutex_unlock(&iaxsl[fr->callno]);
+				return 1;
+			}
+		}
+
+		iax2_lock_owner(fr->callno);
+		if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
+			if (f.subclass.integer == AST_CONTROL_BUSY) {
+				iaxs[fr->callno]->owner->hangupcause = AST_CAUSE_BUSY;
+			} else if (f.subclass.integer == AST_CONTROL_CONGESTION) {
+				iaxs[fr->callno]->owner->hangupcause = AST_CAUSE_CONGESTION;
+			}
+			ast_channel_unlock(iaxs[fr->callno]->owner);
+		}
+	}
+
+	if (f.frametype == AST_FRAME_CONTROL
+		&& f.subclass.integer == AST_CONTROL_CONNECTED_LINE) {
+		struct ast_party_connected_line connected;
+
+		/*
+		 * Process a received connected line update.
+		 *
+		 * Initialize defaults.
+		 */
 		ast_party_connected_line_init(&connected);
 		connected.id.number.presentation = iaxs[fr->callno]->calling_pres;
 		connected.id.name.presentation = iaxs[fr->callno]->calling_pres;
@@ -11613,6 +11733,7 @@
 		}
 		ast_party_connected_line_free(&connected);
 	}
+
 	/* Common things */
 	f.src = "IAX2";
 	f.mallocd = 0;

Modified: certified/branches/1.8.15/configs/iax.conf.sample
URL: http://svnview.digium.com/svn/asterisk/certified/branches/1.8.15/configs/iax.conf.sample?view=diff&rev=407732&r1=407731&r2=407732
==============================================================================
--- certified/branches/1.8.15/configs/iax.conf.sample (original)
+++ certified/branches/1.8.15/configs/iax.conf.sample Fri Feb  7 13:01:01 2014
@@ -345,12 +345,12 @@
 ;
 ; Call token validation can be set as optional for a single IP address or IP
 ; address range by using the 'calltokenoptional' option. 'calltokenoptional' is
-; only a global option.  
+; only a global option.
 ;
 ;calltokenoptional=209.16.236.73/255.255.255.0
 ;
 ; By setting 'requirecalltoken=no', call token validation becomes optional for
-; that peer/user.  By setting 'requirecalltoken=auto', call token validation 
+; that peer/user.  By setting 'requirecalltoken=auto', call token validation
 ; is optional until a call token supporting peer registers successfully using
 ; call token validation.  This is used as an indication that from now on, we
 ; can require it from this peer.  So, requirecalltoken is internally set to yes.
@@ -380,7 +380,7 @@
 ; has been disabled.  Unlike the 'maxcallnumbers' option, this limit is not
 ; separate for each individual IP address.  Any connection resulting in a
 ; non-call token validated call number being allocated contributes to this
-; limit.  For use cases, see the call token user guide.  This option's 
+; limit.  For use cases, see the call token user guide.  This option's
 ; default value of 8192 should be sufficient in most cases.
 ;
 ;maxcallnumbers_nonvalidated=1024
@@ -389,7 +389,7 @@
 ; for specific IP addresses and IP address ranges.  These limits take precedence
 ; over the global 'maxcallnumbers' option, but may still be overridden by a
 ; peer defined 'maxcallnumbers' entry.  Note that these limits take effect
-; for every individual address within the range, not the range as a whole. 
+; for every individual address within the range, not the range as a whole.
 ;
 ;[callnumberlimits]
 ;10.1.1.0/255.255.255.0 = 24
@@ -530,6 +530,19 @@
 ; suggested to the other side as well if it is for example a phone instead of
 ; another PBX.
 ;
+;connectedline=yes ; Set if connected line and redirecting information updates
+;                  ; are passed between Asterisk servers for this peer.
+;                  ; yes - Sending and receiving updates are enabled.
+;                  ; send - Only send updates.
+;                  ; receive - Only process received updates.
+;                  ; no - Sending and receiving updates are disabled.
+;                  ; Default is "no".
+;                  ;
+;                  ; Note: Because of an incompatibility between Asterisk v1.4
+;                  ; and Asterisk v1.8 or later, this option must be set
+;                  ; to "no" toward the Asterisk v1.4 peer.  A symptom of the
+;                  ; incompatibility is the call gets disconnected unexpectedly.
+
 
 ;[dynamichost]
 ;host=dynamic

Modified: certified/branches/1.8.15/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/certified/branches/1.8.15/include/asterisk/frame.h?view=diff&rev=407732&r1=407731&r2=407732
==============================================================================
--- certified/branches/1.8.15/include/asterisk/frame.h (original)
+++ certified/branches/1.8.15/include/asterisk/frame.h Fri Feb  7 13:01:01 2014
@@ -304,6 +304,18 @@
 /*! Reserved bit - do not use */
 #define AST_FORMAT_RESERVED   (1ULL << 63)
 
+/*!
+ * \brief Internal control frame subtype field values.
+ *
+ * \warning
+ * IAX2 sends these values out over the wire.  To prevent future
+ * incompatibilities, pick the next value in the enum from whatever
+ * is on the current trunk.  If you lose the merge race you need to
+ * fix the previous branches to match what is on trunk.  In addition
+ * you need to change chan_iax2 to explicitly allow the control
+ * frame over the wire if it makes sense for the frame to be passed
+ * to another Asterisk instance.
+ */
 enum ast_control_frame_type {
 	AST_CONTROL_HANGUP = 1,			/*!< Other end has hungup */
 	AST_CONTROL_RING = 2,			/*!< Local ring */
@@ -336,7 +348,21 @@
 	AST_CONTROL_END_OF_Q = 29,		/*!< Indicate that this position was the end of the channel queue for a softhangup. */
 	AST_CONTROL_CUSTOM = 200,		/*!< Indicate a custom channel driver specific payload.  Look in custom_control_frame.h for how to define and use this frame. */
 	AST_CONTROL_INCOMPLETE = 30,	/*!< Indication that the extension dialed is incomplete */
-	AST_CONTROL_UPDATE_RTP_PEER = 31, /*!< Interrupt the bridge and have it update the peer */
+	AST_CONTROL_UPDATE_RTP_PEER = 32, /*!< Interrupt the bridge and have it update the peer */
+
+	/*
+	 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+	 *
+	 * IAX2 sends these values out over the wire.  To prevent future
+	 * incompatibilities, pick the next value in the enum from whatever
+	 * is on the current trunk.  If you lose the merge race you need to
+	 * fix the previous branches to match what is on trunk.  In addition
+	 * you need to change chan_iax2 to explicitly allow the control
+	 * frame over the wire if it makes sense for the frame to be passed
+	 * to another Asterisk instance.
+	 *
+	 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+	 */
 };
 
 enum ast_frame_read_action {




More information about the asterisk-commits mailing list