summaryrefslogtreecommitdiff
path: root/channels/chan_iax2.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels/chan_iax2.c')
-rw-r--r--channels/chan_iax2.c159
1 files changed, 146 insertions, 13 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index bb8c9eb5b..abeade87a 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -1332,6 +1332,103 @@ static void iax2_lock_owner(int callno)
}
}
+/*!
+ * \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:
+ case AST_CONTROL_MCID:
+ 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_PVT_CAUSE_CODE:
+ /* Intended only for the sending machine's local channel structure. */
+ case AST_CONTROL_STREAM_STOP:
+ case AST_CONTROL_STREAM_SUSPEND:
+ case AST_CONTROL_STREAM_RESTART:
+ case AST_CONTROL_STREAM_REVERSE:
+ case AST_CONTROL_STREAM_FORWARD:
+ /* None of these playback stream control frames should go across the link. */
+ case AST_CONTROL_RECORD_CANCEL:
+ case AST_CONTROL_RECORD_STOP:
+ case AST_CONTROL_RECORD_SUSPEND:
+ case AST_CONTROL_RECORD_MUTE:
+ /* None of these media recording control frames should go across the link. */
+ break;
+ }
+ return is_allowed;
+}
+
static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
{
/* The MWI subscriptions exist just so the core knows we care about those
@@ -5615,8 +5712,13 @@ static int iax2_indicate(struct ast_channel *c, int condition, const void *data,
}
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;
case AST_CONTROL_PVT_CAUSE_CODE:
res = -1;
@@ -7557,6 +7659,12 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig
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);
}
@@ -10417,13 +10525,6 @@ static int socket_process_helper(struct iax2_thread *thread)
iaxs[fr->callno]->videoformat = ast_format_to_old_bitfield(&f.subclass.format);
}
}
- if (f.frametype == AST_FRAME_CONTROL && iaxs[fr->callno]->owner) {
- if (f.subclass.integer == AST_CONTROL_BUSY) {
- ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_BUSY);
- } else if (f.subclass.integer == AST_CONTROL_CONGESTION) {
- ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_CONGESTION);
- }
- }
if (f.frametype == AST_FRAME_IAX) {
AST_SCHED_DEL(sched, iaxs[fr->callno]->initid);
/* Handle the IAX pseudo frame itself */
@@ -11607,17 +11708,48 @@ immediatedial:
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;
+ }
+ }
+
+ iax2_lock_owner(fr->callno);
+ if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
+ if (f.subclass.integer == AST_CONTROL_BUSY) {
+ ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_BUSY);
+ } else if (f.subclass.integer == AST_CONTROL_CONGESTION) {
+ ast_channel_hangupcause_set(iaxs[fr->callno]->owner, 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;
- /* Initialize defaults */
+ /*
+ * 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;
@@ -11640,6 +11772,7 @@ immediatedial:
}
ast_party_connected_line_free(&connected);
}
+
/* Common things */
f.src = "IAX2";
f.mallocd = 0;