}
}
+/*!
+ * \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
}
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;
}
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);
}
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) {
ast_sched_thread_del(sched, iaxs[fr->callno]->initid);
/* Handle the IAX pseudo frame itself */
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;
}
+ 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;
+ }
+ }
- /* Initialize defaults */
+ 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;
}
ast_party_connected_line_free(&connected);
}
+
/* Common things */
f.src = "IAX2";
f.mallocd = 0;
;
; 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.
; 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
; 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
; 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
/*! 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 */
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 {