ussd: Send USSD on call setup on MSC errors
Send an USSD message to the mobile station requesting a connection for a call or a SMS when the link to the MSC is down or in the grace period. The messages can be set (and this feature activated) by setting bsc/missing-msc-text resp. msc/bsc-grace-text via the vty. The generation of both messages has been tested manually. Ticket: OW#957
This commit is contained in:
parent
323d2f5a47
commit
3ccb86bedc
|
@ -7,6 +7,13 @@
|
|||
|
||||
#define BSS_SEND_USSD 1
|
||||
|
||||
enum bsc_con {
|
||||
BSC_CON_SUCCESS,
|
||||
BSC_CON_REJECT_NO_LINK,
|
||||
BSC_CON_REJECT_RF_GRACE,
|
||||
BSC_CON_NO_MEM,
|
||||
};
|
||||
|
||||
struct sccp_connection;
|
||||
struct osmo_msc_data;
|
||||
struct bsc_msc_connection;
|
||||
|
@ -34,8 +41,8 @@ struct bsc_api *osmo_bsc_api();
|
|||
|
||||
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg);
|
||||
int bsc_open_connection(struct osmo_bsc_sccp_con *sccp, struct msgb *msg);
|
||||
int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
|
||||
struct osmo_msc_data *msc);
|
||||
enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
|
||||
struct osmo_msc_data *msc);
|
||||
int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp);
|
||||
|
||||
struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *);
|
||||
|
|
|
@ -86,6 +86,9 @@ struct osmo_msc_data {
|
|||
|
||||
/* ussd msc connection lost text */
|
||||
char *ussd_msc_lost_txt;
|
||||
|
||||
/* ussd text when MSC has entered the grace period */
|
||||
char *ussd_grace_txt;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -103,6 +106,9 @@ struct osmo_bsc_data {
|
|||
char *rf_ctrl_name;
|
||||
struct osmo_bsc_rf *rf_ctrl;
|
||||
int auto_off_timeout;
|
||||
|
||||
/* ussd text when there is no MSC available */
|
||||
char *ussd_no_msc_txt;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <openbsc/osmo_msc_data.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <openbsc/gsm_04_80.h>
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_08_08.h>
|
||||
#include <osmocom/gsm/gsm0808.h>
|
||||
|
||||
|
@ -85,6 +87,47 @@ static void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
|
|||
queue_msg_or_return(resp);
|
||||
}
|
||||
|
||||
static void bsc_send_ussd_notification(struct gsm_subscriber_connection *conn,
|
||||
struct msgb *msg, const char *text)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
int8_t pdisc;
|
||||
uint8_t mtype;
|
||||
int drop_message = 1;
|
||||
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
if (!msg || msgb_l3len(msg) < sizeof(*gh))
|
||||
return;
|
||||
|
||||
gh = msgb_l3(msg);
|
||||
pdisc = gh->proto_discr & 0x0f;
|
||||
mtype = gh->msg_type & 0xbf;
|
||||
|
||||
/* Is CM service request? */
|
||||
if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) {
|
||||
struct gsm48_service_request *cm;
|
||||
|
||||
cm = (struct gsm48_service_request *) &gh->data[0];
|
||||
|
||||
/* Is type SMS or call? */
|
||||
if (cm->cm_service_type == GSM48_CMSERV_SMS)
|
||||
drop_message = 0;
|
||||
else if (cm->cm_service_type == GSM48_CMSERV_MO_CALL_PACKET)
|
||||
drop_message = 0;
|
||||
}
|
||||
|
||||
if (drop_message) {
|
||||
LOGP(DMSC, LOGL_DEBUG, "Skipping (not sending) USSD message: '%s'\n", text);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGP(DMSC, LOGL_INFO, "Sending USSD message: '%s'\n", text);
|
||||
gsm0480_send_ussdNotify(conn, 1, text);
|
||||
gsm0480_send_releaseComplete(conn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Instruct to reserve data for a new connectiom, create the complete
|
||||
* layer three message, send it to open the connection.
|
||||
|
@ -100,6 +143,7 @@ static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
|
|||
msc = bsc_find_msc(conn, msg);
|
||||
if (!msc) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to find a MSC for a connection.\n");
|
||||
bsc_send_ussd_notification(conn, msg, conn->bts->network->bsc_data->ussd_no_msc_txt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -112,10 +156,22 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
|
|||
struct msgb *resp;
|
||||
uint16_t network_code;
|
||||
uint16_t country_code;
|
||||
enum bsc_con ret;
|
||||
|
||||
/* allocate resource for a new connection */
|
||||
if (bsc_create_new_connection(conn, msc) != 0)
|
||||
ret = bsc_create_new_connection(conn, msc);
|
||||
|
||||
if (ret != BSC_CON_SUCCESS) {
|
||||
/* allocation has failed */
|
||||
if (ret == BSC_CON_REJECT_NO_LINK)
|
||||
bsc_send_ussd_notification(conn, msg, msc->ussd_msc_lost_txt);
|
||||
else if (ret == BSC_CON_REJECT_RF_GRACE)
|
||||
bsc_send_ussd_notification(conn, msg, msc->ussd_grace_txt);
|
||||
|
||||
return BSC_API_CONN_POL_REJECT;
|
||||
}
|
||||
|
||||
/* check return value, if failed check msg for and send USSD */
|
||||
|
||||
network_code = get_network_code_for_msc(conn->sccp_con->msc);
|
||||
country_code = get_country_code_for_msc(conn->sccp_con->msc);
|
||||
|
|
|
@ -188,35 +188,35 @@ int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
|
||||
enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
|
||||
struct osmo_msc_data *msc)
|
||||
{
|
||||
struct osmo_bsc_sccp_con *bsc_con;
|
||||
struct sccp_connection *sccp;
|
||||
|
||||
/* This should not trigger */
|
||||
if (!msc->msc_con->is_authenticated) {
|
||||
if (!msc || !msc->msc_con->is_authenticated) {
|
||||
LOGP(DMSC, LOGL_ERROR,
|
||||
"How did this happen? MSC is not connected. Dropping.\n");
|
||||
return -1;
|
||||
return BSC_CON_REJECT_NO_LINK;
|
||||
}
|
||||
|
||||
if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) {
|
||||
LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
|
||||
return -1;
|
||||
return BSC_CON_REJECT_RF_GRACE;
|
||||
}
|
||||
|
||||
sccp = sccp_connection_socket();
|
||||
if (!sccp) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
|
||||
return -ENOMEM;
|
||||
return BSC_CON_NO_MEM;
|
||||
}
|
||||
|
||||
bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
|
||||
if (!bsc_con) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to allocate.\n");
|
||||
sccp_connection_free(sccp);
|
||||
return -1;
|
||||
return BSC_CON_NO_MEM;
|
||||
}
|
||||
|
||||
/* callbacks */
|
||||
|
@ -237,7 +237,7 @@ int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
|
|||
bsc_con->conn = conn;
|
||||
llist_add_tail(&bsc_con->entry, &active_connections);
|
||||
conn->sccp_con = bsc_con;
|
||||
return 0;
|
||||
return BSC_CON_SUCCESS;
|
||||
}
|
||||
|
||||
int bsc_open_connection(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
|
||||
|
|
|
@ -122,6 +122,11 @@ static void write_msc(struct vty *vty, struct osmo_msc_data *msc)
|
|||
else
|
||||
vty_out(vty, " no bsc-msc-lost-text%s", VTY_NEWLINE);
|
||||
|
||||
if (msc->ussd_grace_txt && msc->ussd_grace_txt[0])
|
||||
vty_out(vty, " bsc-grace-text %s%s", msc->ussd_grace_txt, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " no bsc-grace-text%s", VTY_NEWLINE);
|
||||
|
||||
if (msc->audio_length != 0) {
|
||||
int i;
|
||||
|
||||
|
@ -182,6 +187,11 @@ static int config_write_bsc(struct vty *vty)
|
|||
vty_out(vty, " bsc-auto-rf-off %d%s",
|
||||
bsc->auto_off_timeout, VTY_NEWLINE);
|
||||
|
||||
if (bsc->ussd_no_msc_txt && bsc->ussd_no_msc_txt[0])
|
||||
vty_out(vty, " missing-msc-text %s%s", bsc->ussd_no_msc_txt, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " no missing-msc-text%s", VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -384,7 +394,7 @@ DEFUN(cfg_net_msc_no_welcome_ussd,
|
|||
struct osmo_msc_data *data = osmo_msc_data(vty);
|
||||
|
||||
talloc_free(data->ussd_welcome_txt);
|
||||
data->ussd_welcome_txt = 0;
|
||||
data->ussd_welcome_txt = NULL;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -417,6 +427,63 @@ DEFUN(cfg_net_msc_no_lost_ussd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_msc_grace_ussd,
|
||||
cfg_net_msc_grace_ussd_cmd,
|
||||
"bsc-grace-text .TEXT",
|
||||
"Set the USSD notification to be sent when the MSC has entered the grace period\n" "Text to be sent\n")
|
||||
{
|
||||
struct osmo_msc_data *data = osmo_msc_data(vty);
|
||||
char *str = argv_concat(argv, argc, 0);
|
||||
if (!str)
|
||||
return CMD_WARNING;
|
||||
|
||||
bsc_replace_string(osmo_bsc_data(vty), &data->ussd_grace_txt, str);
|
||||
talloc_free(str);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_msc_no_grace_ussd,
|
||||
cfg_net_msc_no_grace_ussd_cmd,
|
||||
"no bsc-grace-text",
|
||||
NO_STR "Clear the USSD notification to be sent when the MSC has entered the grace period\n")
|
||||
{
|
||||
struct osmo_msc_data *data = osmo_msc_data(vty);
|
||||
|
||||
talloc_free(data->ussd_grace_txt);
|
||||
data->ussd_grace_txt = NULL;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_bsc_missing_msc_ussd,
|
||||
cfg_net_bsc_missing_msc_ussd_cmd,
|
||||
"missing-msc-text .TEXT",
|
||||
"Set the USSD notification to be send when a MSC has not been found.\n" "Text to be sent\n")
|
||||
{
|
||||
struct osmo_bsc_data *data = osmo_bsc_data(vty);
|
||||
char *txt = argv_concat(argv, argc, 0);
|
||||
if (!txt)
|
||||
return CMD_WARNING;
|
||||
|
||||
bsc_replace_string(data, &data->ussd_no_msc_txt, txt);
|
||||
talloc_free(txt);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_bsc_no_missing_msc_text,
|
||||
cfg_net_bsc_no_missing_msc_text_cmd,
|
||||
"no missing-msc-text",
|
||||
NO_STR "Clear the USSD notification to be send when a MSC has not been found.\n")
|
||||
{
|
||||
struct osmo_bsc_data *data = osmo_bsc_data(vty);
|
||||
|
||||
talloc_free(data->ussd_no_msc_txt);
|
||||
data->ussd_no_msc_txt = 0;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFUN(cfg_net_msc_type,
|
||||
cfg_net_msc_type_cmd,
|
||||
"type (normal|local)",
|
||||
|
@ -615,6 +682,8 @@ int bsc_vty_init_extra(void)
|
|||
install_element(BSC_NODE, &cfg_net_rf_socket_cmd);
|
||||
install_element(BSC_NODE, &cfg_net_rf_off_time_cmd);
|
||||
install_element(BSC_NODE, &cfg_net_no_rf_off_time_cmd);
|
||||
install_element(BSC_NODE, &cfg_net_bsc_missing_msc_ussd_cmd);
|
||||
install_element(BSC_NODE, &cfg_net_bsc_no_missing_msc_text_cmd);
|
||||
|
||||
install_node(&msc_node, config_write_msc);
|
||||
bsc_install_default(MSC_NODE);
|
||||
|
@ -631,6 +700,8 @@ int bsc_vty_init_extra(void)
|
|||
install_element(MSC_NODE, &cfg_net_msc_no_welcome_ussd_cmd);
|
||||
install_element(MSC_NODE, &cfg_net_msc_lost_ussd_cmd);
|
||||
install_element(MSC_NODE, &cfg_net_msc_no_lost_ussd_cmd);
|
||||
install_element(MSC_NODE, &cfg_net_msc_grace_ussd_cmd);
|
||||
install_element(MSC_NODE, &cfg_net_msc_no_grace_ussd_cmd);
|
||||
install_element(MSC_NODE, &cfg_net_msc_type_cmd);
|
||||
install_element(MSC_NODE, &cfg_net_msc_emerg_cmd);
|
||||
install_element(MSC_NODE, &cfg_net_msc_local_prefix_cmd);
|
||||
|
|
|
@ -207,7 +207,7 @@ class TestVTYBSC(TestVTYGenericBSC):
|
|||
self.vty.command("msc 0")
|
||||
self.assertEquals(self.vty.node(), 'config-msc')
|
||||
|
||||
def testUssdNotifications(self):
|
||||
def testUssdNotificationsMsc(self):
|
||||
self.vty.enable()
|
||||
self.vty.command("configure terminal")
|
||||
self.vty.command("msc")
|
||||
|
@ -215,10 +215,12 @@ class TestVTYBSC(TestVTYGenericBSC):
|
|||
# Test invalid input
|
||||
self.vty.verify("bsc-msc-lost-text", ['% Command incomplete.'])
|
||||
self.vty.verify("bsc-welcome-text", ['% Command incomplete.'])
|
||||
self.vty.verify("bsc-grace-text", ['% Command incomplete.'])
|
||||
|
||||
# Enable USSD notifications
|
||||
self.vty.verify("bsc-msc-lost-text MSC disconnected", [''])
|
||||
self.vty.verify("bsc-welcome-text Hello MS", [''])
|
||||
self.vty.verify("bsc-grace-text In grace period", [''])
|
||||
|
||||
# Verify settings
|
||||
res = self.vty.command("write terminal")
|
||||
|
@ -226,17 +228,46 @@ class TestVTYBSC(TestVTYGenericBSC):
|
|||
self.assertEquals(res.find('no bsc-msc-lost-text'), -1)
|
||||
self.assert_(res.find('bsc-welcome-text Hello MS') > 0)
|
||||
self.assertEquals(res.find('no bsc-welcome-text'), -1)
|
||||
self.assert_(res.find('bsc-grace-text In grace period') > 0)
|
||||
self.assertEquals(res.find('no bsc-grace-text'), -1)
|
||||
|
||||
# Now disable it..
|
||||
self.vty.verify("no bsc-msc-lost-text", [''])
|
||||
self.vty.verify("no bsc-welcome-text", [''])
|
||||
self.vty.verify("no bsc-grace-text", [''])
|
||||
|
||||
# Verify settings
|
||||
res = self.vty.command("write terminal")
|
||||
self.assertEquals(res.find('bsc-msc-lost-text MSC disconnected'), -1)
|
||||
self.assert_(res.find('no bsc-msc-lost-text') > 0)
|
||||
self.assert_(res.find('no bsc-welcome-text') > 0)
|
||||
self.assertEquals(res.find('bsc-welcome-text Hello MS'), -1)
|
||||
self.assert_(res.find('no bsc-welcome-text') > 0)
|
||||
self.assertEquals(res.find('bsc-grace-text In grace period'), -1)
|
||||
self.assert_(res.find('no bsc-grace-text') > 0)
|
||||
|
||||
def testUssdNotificationsBsc(self):
|
||||
self.vty.enable()
|
||||
self.vty.command("configure terminal")
|
||||
self.vty.command("bsc")
|
||||
|
||||
# Test invalid input
|
||||
self.vty.verify("missing-msc-text", ['% Command incomplete.'])
|
||||
|
||||
# Enable USSD notifications
|
||||
self.vty.verify("missing-msc-text No MSC found", [''])
|
||||
|
||||
# Verify settings
|
||||
res = self.vty.command("write terminal")
|
||||
self.assert_(res.find('missing-msc-text No MSC found') > 0)
|
||||
self.assertEquals(res.find('no missing-msc-text'), -1)
|
||||
|
||||
# Now disable it..
|
||||
self.vty.verify("no missing-msc-text", [''])
|
||||
|
||||
# Verify settings
|
||||
res = self.vty.command("write terminal")
|
||||
self.assertEquals(res.find('missing-msc-text No MSC found'), -1)
|
||||
self.assert_(res.find('no missing-msc-text') > 0)
|
||||
|
||||
class TestVTYNAT(TestVTYGenericBSC):
|
||||
|
||||
|
|
Loading…
Reference in New Issue