diff --git a/include/osmocom/msc/gsm_data.h b/include/osmocom/msc/gsm_data.h index a90b732af..11b6e8237 100644 --- a/include/osmocom/msc/gsm_data.h +++ b/include/osmocom/msc/gsm_data.h @@ -258,6 +258,9 @@ struct gsm_network { /* Whether we want to use Osmux against BSCs. Controlled via VTY */ enum osmux_usage use_osmux; + + /* Whether to use call waiting on the network */ + bool call_waiting; }; struct osmo_esme; diff --git a/src/libmsc/gsm_04_08_cc.c b/src/libmsc/gsm_04_08_cc.c index e83caa22f..ed74e88bb 100644 --- a/src/libmsc/gsm_04_08_cc.c +++ b/src/libmsc/gsm_04_08_cc.c @@ -1909,6 +1909,25 @@ static int mncc_tx_to_gsm_cc(struct gsm_network *net, const union mncc_msg *msg) GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_DEST_OOO); } + + /* Find valid conn */ + msc_a = msc_a_for_vsub(vsub, true); + + /* If subscriber is BUSY and we do not DO call in call aka "call-waiting" */ + if (!net->call_waiting && msc_a) { + struct gsm_trans *existing_cc_trans = trans_find_by_type(msc_a, TRANS_CC); + if (existing_cc_trans && existing_cc_trans->cc.state != GSM_CSTATE_NULL) { + LOG_TRANS_CAT(existing_cc_trans, DCC, LOGL_NOTICE, + "rx '%s' for subscriber %s with trans state (%s)" + " rejecting with USER_BUSY\n", + get_mncc_name(msg->msg_type), data->called.number, + gsm48_cc_state_name(existing_cc_trans->cc.state)); + return mncc_release_ind(net, NULL, data->callref, + GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_USER_BUSY); + } + } + /* Create transaction */ trans = trans_alloc(net, vsub, TRANS_CC, TRANS_ID_UNASSIGNED, data->callref); @@ -1922,9 +1941,6 @@ static int mncc_tx_to_gsm_cc(struct gsm_network *net, const union mncc_msg *msg) return -ENOMEM; } - /* Find valid conn */ - msc_a = msc_a_for_vsub(vsub, true); - /* If subscriber has no conn */ if (!msc_a) { diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c index 4674e2e68..09aef9168 100644 --- a/src/libmsc/msc_vty.c +++ b/src/libmsc/msc_vty.c @@ -330,6 +330,29 @@ DEFUN(cfg_net_no_per_loc_upd, cfg_net_no_per_loc_upd_cmd, return CMD_SUCCESS; } +DEFUN(cfg_net_call_wait, cfg_net_call_wait_cmd, + "call-waiting", + "Enable Call Waiting on the Network\n") +{ + struct gsm_network *net = vty->index; + + net->call_waiting = true; + + return CMD_SUCCESS; +} + +DEFUN(cfg_net_no_call_wait, cfg_net_no_call_wait_cmd, + "no call-waiting", + NO_STR + "Disable Call Waiting on the Network\n") +{ + struct gsm_network *net = vty->index; + + net->call_waiting = false; + + return CMD_SUCCESS; +} + static int config_write_net(struct vty *vty) { int i; @@ -376,6 +399,9 @@ static int config_write_net(struct vty *vty) gsmnet->emergency.route_to_msisdn, VTY_NEWLINE); } + if (!gsmnet->call_waiting) + vty_out(vty, " no call-waiting%s", VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1946,6 +1972,8 @@ void msc_vty_init(struct gsm_network *msc_network) install_element(GSMNET_NODE, &cfg_net_no_timezone_cmd); install_element(GSMNET_NODE, &cfg_net_per_loc_upd_cmd); install_element(GSMNET_NODE, &cfg_net_no_per_loc_upd_cmd); + install_element(GSMNET_NODE, &cfg_net_call_wait_cmd); + install_element(GSMNET_NODE, &cfg_net_no_call_wait_cmd); install_element(CONFIG_NODE, &cfg_msc_cmd); install_node(&msc_node, config_write_msc); diff --git a/src/osmo-msc/msc_main.c b/src/osmo-msc/msc_main.c index 1083271a9..3860589e7 100644 --- a/src/osmo-msc/msc_main.c +++ b/src/osmo-msc/msc_main.c @@ -216,6 +216,7 @@ struct gsm_network *msc_network_alloc(void *ctx, mgcp_client_conf_init(&net->mgw.conf); net->mgw.tdefs = g_mgw_tdefs; + net->call_waiting = true; return net; } diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty index 0ad390fc5..a4e0e15db 100644 --- a/tests/test_nodes.vty +++ b/tests/test_nodes.vty @@ -26,6 +26,8 @@ OsmoMSC(config-net)# list no timezone periodic location update <6-1530> no periodic location update + call-waiting + no call-waiting OsmoMSC(config-net)# encryption? encryption Encryption options