diff options
Diffstat (limited to 'channels/chan_iax2.c')
-rw-r--r-- | channels/chan_iax2.c | 159 |
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; |