Disconnect calls with incompatible channel types / modes
In case both TCH/H and TCH/F or different codecs are configured and internal MNCC handler is used we might end up in a situation where call legs with incompatible channel types or codecs would be connected resulting in a broken audio. Disconnect such calls with appropriate error message. Fixes: OS#1663
This commit is contained in:
parent
35697b9a10
commit
3ffce19cb4
|
@ -1600,6 +1600,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
|
||||||
struct gsm_bts *bts = lchan->ts->trx->bts;
|
struct gsm_bts *bts = lchan->ts->trx->bts;
|
||||||
struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
|
struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
|
||||||
enum gsm_chan_t lt = lchan->type, rt = remote_lchan->type;
|
enum gsm_chan_t lt = lchan->type, rt = remote_lchan->type;
|
||||||
|
enum gsm48_chan_mode lm = lchan->tch_mode, rm = remote_lchan->tch_mode;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u,%s) and "
|
DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u,%s) and "
|
||||||
|
@ -1614,6 +1615,22 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lt != rt) {
|
||||||
|
LOGP(DCC, LOGL_ERROR, "Cannot patch through call with different"
|
||||||
|
" channel types: local = %s, remote = %s\n",
|
||||||
|
get_value_string(gsm_chan_t_names, lt),
|
||||||
|
get_value_string(gsm_chan_t_names, rt));
|
||||||
|
return -EBADSLT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lm != rm) {
|
||||||
|
LOGP(DCC, LOGL_ERROR, "Cannot patch through call with different"
|
||||||
|
" channel modes: local = %s, remote = %s\n",
|
||||||
|
get_value_string(gsm48_chan_mode_names, lm),
|
||||||
|
get_value_string(gsm48_chan_mode_names, rm));
|
||||||
|
return -EMEDIUMTYPE;
|
||||||
|
}
|
||||||
|
|
||||||
// todo: map between different bts types
|
// todo: map between different bts types
|
||||||
switch (bts->type) {
|
switch (bts->type) {
|
||||||
case GSM_BTS_TYPE_NANOBTS:
|
case GSM_BTS_TYPE_NANOBTS:
|
||||||
|
@ -1851,6 +1868,30 @@ static void gsm48_cc_timeout(void *arg)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* disconnect both calls from the bridge */
|
||||||
|
static inline void disconnect_bridge(struct gsm_network *net,
|
||||||
|
struct gsm_mncc_bridge *bridge, int err)
|
||||||
|
{
|
||||||
|
struct gsm_trans *trans0 = trans_find_by_callref(net, bridge->callref[0]);
|
||||||
|
struct gsm_trans *trans1 = trans_find_by_callref(net, bridge->callref[1]);
|
||||||
|
struct gsm_mncc mx_rel;
|
||||||
|
if (!trans0 || !trans1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DEBUGP(DCC, "Failed to bridge TCH for calls %x <-> %x :: %s \n",
|
||||||
|
trans0->callref, trans1->callref, strerror(err));
|
||||||
|
|
||||||
|
memset(&mx_rel, 0, sizeof(struct gsm_mncc));
|
||||||
|
mncc_set_cause(&mx_rel, GSM48_CAUSE_LOC_INN_NET,
|
||||||
|
GSM48_CC_CAUSE_CHAN_UNACCEPT);
|
||||||
|
|
||||||
|
mx_rel.callref = trans0->callref;
|
||||||
|
gsm48_cc_tx_disconnect(trans0, &mx_rel);
|
||||||
|
|
||||||
|
mx_rel.callref = trans1->callref;
|
||||||
|
gsm48_cc_tx_disconnect(trans1, &mx_rel);
|
||||||
|
}
|
||||||
|
|
||||||
static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
|
static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
|
||||||
int sec, int micro)
|
int sec, int micro)
|
||||||
{
|
{
|
||||||
|
@ -3221,7 +3262,10 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
|
||||||
/* handle special messages */
|
/* handle special messages */
|
||||||
switch(msg_type) {
|
switch(msg_type) {
|
||||||
case MNCC_BRIDGE:
|
case MNCC_BRIDGE:
|
||||||
return tch_bridge(net, arg);
|
rc = tch_bridge(net, arg);
|
||||||
|
if (rc < 0)
|
||||||
|
disconnect_bridge(net, arg, -rc);
|
||||||
|
return rc;
|
||||||
case MNCC_FRAME_DROP:
|
case MNCC_FRAME_DROP:
|
||||||
return tch_recv_mncc(net, data->callref, 0);
|
return tch_recv_mncc(net, data->callref, 0);
|
||||||
case MNCC_FRAME_RECV:
|
case MNCC_FRAME_RECV:
|
||||||
|
|
Loading…
Reference in New Issue