summaryrefslogtreecommitdiffstats
path: root/openbsc/src/osmo-bsc
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2013-09-11 10:46:55 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2013-09-11 20:18:42 +0200
commit56595f8647d6ee5de1c74077e83ca438102b5ff4 (patch)
tree54d596cb3e32242d1dad87e555bfe2a8020eea6b /openbsc/src/osmo-bsc
parent3ffd9bc0a4efe03022d87513dbde3efc7b4fb8e6 (diff)
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
Diffstat (limited to 'openbsc/src/osmo-bsc')
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_api.c58
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_sccp.c14
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_vty.c73
3 files changed, 136 insertions, 9 deletions
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c
index df8c0444f..675bbb20e 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_api.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_api.c
@@ -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);
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
index 87f415e0b..aa8c79ca6 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
@@ -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)
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_vty.c b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
index 90b0a0cd8..fceaa4ad6 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_vty.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
@@ -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);