Signed-off-by: Max max.suraev@fairwaves.co --- openbsc/include/openbsc/Makefile.am | 2 +- openbsc/include/openbsc/db.h | 4 + openbsc/include/openbsc/gsm_04_80.h | 36 ++++++-- openbsc/include/openbsc/ss.h | 10 +++ openbsc/include/openbsc/ussd.h | 10 --- openbsc/src/libmsc/Makefile.am | 2 +- openbsc/src/libmsc/db.c | 89 +++++++++++++++++++ openbsc/src/libmsc/gsm_04_08.c | 4 +- openbsc/src/libmsc/gsm_04_80.c | 65 ++++++++------ openbsc/src/libmsc/ss.c | 173 ++++++++++++++++++++++++++++++++++++ openbsc/src/libmsc/ussd.c | 87 ------------------ 11 files changed, 349 insertions(+), 133 deletions(-) create mode 100644 openbsc/include/openbsc/ss.h delete mode 100644 openbsc/include/openbsc/ussd.h create mode 100644 openbsc/src/libmsc/ss.c delete mode 100644 openbsc/src/libmsc/ussd.c
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 254f43d..b19c413 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -2,7 +2,7 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \ gsm_subscriber.h gsm_04_11.h debug.h signal.h \ misdn.h chan_alloc.h paging.h ctrl.h \ trau_mux.h rs232.h openbscdefines.h rtp_proxy.h \ - bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \ + bsc_rll.h mncc.h transaction.h ss.h gsm_04_80.h \ silent_call.h mgcp.h meas_rep.h rest_octets.h \ system_information.h handover.h mgcp_internal.h \ vty.h socket.h e1_config.h trau_upqueue.h token_auth.h \ diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index 6699a86..73c061b 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -79,4 +79,8 @@ int db_store_counter(struct osmo_counter *ctr); struct rate_ctr_group; int db_store_rate_ctr_group(struct rate_ctr_group *ctrg);
+/* Supplementary Services */ +int db_ss_interrogate_status(struct gsm_subscriber *subscr, uint8_t ss_code, uint8_t bs_code, uint8_t *ss_status); +int db_ss_set_status(struct gsm_subscriber *subscr, uint8_t ss_code, uint8_t bs_code, uint8_t ss_status); + #endif /* _DB_H */ diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index 0a60652..7139f95 100644 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -3,16 +3,42 @@
#include <osmocom/core/msgb.h> #include <osmocom/gsm/protocol/gsm_04_80.h> +#include <osmocom/gsm/protocol/gsm_09_02.h> #include <osmocom/gsm/gsm0480.h>
struct gsm_subscriber_connection;
+/* FIXME: replace with libosmocore functions */ +static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag) +{ + uint8_t *data = msgb_push(msgb, 2); + + data[0] = tag; + data[1] = msgb->len - 2; + return data; +} + +static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag, + uint8_t value) +{ + uint8_t *data = msgb_push(msgb, 3); + + data[0] = tag; + data[1] = 1; + data[2] = value; + return data; +} + int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, - const struct msgb *in_msg, const char* response_text, - const struct ussd_request *req); -int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, - const struct msgb *msg, - const struct ussd_request *request); + const char* response_text, + const struct ss_request *req); +int gsm0480_send_ss_return_result(struct gsm_subscriber_connection *conn, + const struct ss_request *req, + struct msgb *msg); +int gsm0480_send_ss_reject(struct gsm_subscriber_connection *conn, + const struct ss_request *request, + uint8_t problem_category, + uint8_t problem_code);
int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text); int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn); diff --git a/openbsc/include/openbsc/ss.h b/openbsc/include/openbsc/ss.h new file mode 100644 index 0000000..92ce913 --- /dev/null +++ b/openbsc/include/openbsc/ss.h @@ -0,0 +1,10 @@ +#ifndef _SS_H +#define _SS_H + +/* Handler function for mobile-originated SS messages */ + +#include <osmocom/core/msgb.h> + +int handle_rcv_ss(struct gsm_subscriber_connection *conn, struct msgb *msg); + +#endif diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h deleted file mode 100644 index 2665468..0000000 --- a/openbsc/include/openbsc/ussd.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _USSD_H -#define _USSD_H - -/* Handler function for mobile-originated USSD messages */ - -#include <osmocom/core/msgb.h> - -int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg); - -#endif diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index aa7d8ae..de0ce66 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -16,7 +16,7 @@ libmsc_a_SOURCES = auth.c \ silent_call.c \ sms_queue.c \ token_auth.c \ - ussd.c \ + ss.c \ vty_interface_layer3.c \ transaction.c \ osmo_msc.c ctrl_commands.c meas_feed.c diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c index 428f99b..25dd00e 100644 --- a/openbsc/src/libmsc/db.c +++ b/openbsc/src/libmsc/db.c @@ -41,6 +41,8 @@ /* Semi-Private-Interface (SPI) for the subscriber code */ void subscr_direct_free(struct gsm_subscriber *subscr);
+#include <osmocom/gsm/protocol/gsm_09_02.h> + static char *db_basename = NULL; static char *db_dirname = NULL; static dbi_conn conn; @@ -174,6 +176,15 @@ static const char *create_stmts[] = { "sres BLOB NOT NULL, " "kc BLOB NOT NULL " ")", + "CREATE TABLE IF NOT EXISTS SS_Status (" + "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + "subscriber INTEGER NOT NULL, " + "ss_code TINYINT UNSIGNED NOT NULL, " + "bs_code TINYINT UNSIGNED, " + "ss_status TINYINT UNSIGNED NOT NULL, " + "UNIQUE(subscriber, ss_code, bs_code), " + "FOREIGN KEY(subscriber) REFERENCES Subscriber (id) ON DELETE CASCADE ON UPDATE CASCADE " + ")", };
void db_error_func(dbi_conn conn, void *data) @@ -1724,3 +1735,81 @@ int db_store_rate_ctr_group(struct rate_ctr_group *ctrg)
return 0; } + +int db_ss_interrogate_status(struct gsm_subscriber *subscr, uint8_t ss_code, uint8_t bs_code, uint8_t *ss_status) +{ + char buf[32]; + dbi_result result; + + /* Copy the id to a string as queryf with %llu is failing */ + sprintf(buf, "%llu", subscr->id); + result = dbi_conn_queryf(conn, + "SELECT ss_status FROM SS_Status " + "WHERE subscriber = %s " + "AND ss_code = %i AND bs_code = %i", + buf, ss_code, bs_code); + + if (!result) { + LOGP(DDB, + LOGL_ERROR, + "Failed to query ss_status for subscriber %llu, " + "ss code 0x%02X, bs code 0x%02X\n", + subscr->id, ss_code, bs_code); + return -EIO; + } + if (!dbi_result_next_row(result)) { + DEBUGP(DDB, + "Failed to find ss_status for subscriber %llu, " + "ss code 0x%02X, bs code 0x%02X\n", + subscr->id, ss_code, bs_code); + dbi_result_free(result); + return -ENOENT; + } + + *ss_status = dbi_result_get_uint(result, "ss_status"); + DEBUGP(DDB, + "Found ss_status for subscriber %llu, " + "ss code 0x%02X, bs code 0x%02X: P:%d R:%d A:%d Q:%d\n", + subscr->id, ss_code, bs_code, + (*ss_status & GSM0902_SS_STATUS_P_BIT) && 1, + (*ss_status & GSM0902_SS_STATUS_R_BIT) && 1, + (*ss_status & GSM0902_SS_STATUS_A_BIT) && 1, + (*ss_status & GSM0902_SS_STATUS_Q_BIT) && 1); + + dbi_result_free(result); + return 0; +} + +int db_ss_set_status(struct gsm_subscriber *subscr, uint8_t ss_code, uint8_t bs_code, uint8_t ss_status) +{ + char buf[32]; + dbi_result result; + + /* Copy the id to a string as queryf with %llu is failing */ + sprintf(buf, "%llu", subscr->id); + + result = dbi_conn_queryf(conn, + "UPDATE SS_Status SET ss_status = %i " + "WHERE subscriber = %s AND " + "ss_code = %i AND bs_code = %i", + ss_status, buf, ss_code, bs_code); + + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to set ss_status for subscriber %llu\n", + subscr->id); + return -EIO; + } + + DEBUGP(DDB, + "Set ss_status for subscriber %llu, " + "ss code 0x%02X, bs code 0x%02X: P:%d R:%d A:%d Q:%d\n", + subscr->id, ss_code, bs_code, + (ss_status & GSM0902_SS_STATUS_P_BIT) && 1, + (ss_status & GSM0902_SS_STATUS_R_BIT) && 1, + (ss_status & GSM0902_SS_STATUS_A_BIT) && 1, + (ss_status & GSM0902_SS_STATUS_Q_BIT) && 1); + + dbi_result_free(result); + return 0; +} diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 29ab2ba..01f8f32 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -47,7 +47,7 @@ #include <openbsc/trau_mux.h> #include <openbsc/rtp_proxy.h> #include <openbsc/transaction.h> -#include <openbsc/ussd.h> +#include <openbsc/ss.h> #include <openbsc/silent_call.h> #include <openbsc/bsc_api.h> #include <openbsc/osmo_msc.h> @@ -3340,7 +3340,7 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) break; case GSM48_PDISC_NC_SS: release_anchor(conn); - rc = handle_rcv_ussd(conn, msg); + rc = handle_rcv_ss(conn, msg); break; default: LOGP(DRLL, LOGL_NOTICE, "Unknown " diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c index b30f9ee..b20521a 100644 --- a/openbsc/src/libmsc/gsm_04_80.c +++ b/openbsc/src/libmsc/gsm_04_80.c @@ -39,31 +39,11 @@ #include <osmocom/core/msgb.h> #include <osmocom/gsm/tlv.h>
-static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag) -{ - uint8_t *data = msgb_push(msgb, 2); - - data[0] = tag; - data[1] = msgb->len - 2; - return data; -} - -static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag, - uint8_t value) -{ - uint8_t *data = msgb_push(msgb, 3); - - data[0] = tag; - data[1] = 1; - data[2] = value; - return data; -} -
/* Send response to a mobile-originated ProcessUnstructuredSS-Request */ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, - const struct msgb *in_msg, const char *response_text, - const struct ussd_request *req) + const char *response_text, + const struct ss_request *req) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -109,16 +89,47 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, return gsm0808_submit_dtap(conn, msg, 0, 0); }
-int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, - const struct msgb *in_msg, - const struct ussd_request *req) +/* Send response to a mobile-originated Invoke */ +int gsm0480_send_ss_return_result(struct gsm_subscriber_connection *conn, + const struct ss_request *req, + struct msgb *msg) +{ + struct gsm48_hdr *gh; + + /* Pre-pend the operation code */ + msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode); + + /* Wrap the contents as a sequence */ + msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); + + /* Pre-pend the invoke ID */ + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); + + /* Wrap this up as a Return Result component */ + msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT); + + /* Wrap the component in a Facility message */ + msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); + + /* And finally pre-pend the L3 header */ + gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id + | (1<<7); /* TI direction = 1 */ + gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; + + return gsm0808_submit_dtap(conn, msg, 0, 0); +} + +int gsm0480_send_ss_reject(struct gsm_subscriber_connection *conn, + const struct ss_request *req, + uint8_t problem_category, + uint8_t problem_code) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh;
/* First insert the problem code */ - msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL, - GSM_0480_GEN_PROB_CODE_UNRECOGNISED); + msgb_push_TLV1(msg, problem_category, problem_code);
/* Before it insert the invoke ID */ msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); diff --git a/openbsc/src/libmsc/ss.c b/openbsc/src/libmsc/ss.c new file mode 100644 index 0000000..44a01ec --- /dev/null +++ b/openbsc/src/libmsc/ss.c @@ -0,0 +1,173 @@ +/* Network-specific handling of mobile-originated SSs. */ + +/* (C) 2008-2009 by Harald Welte laforge@gnumonks.org + * (C) 2008, 2009 by Holger Hans Peter Freyther zecke@selfish.org + * (C) 2009 by Mike Haben michael.haben@btinternet.com + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +/* This module defines the network-specific handling of mobile-originated + SS messages. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <openbsc/db.h> +#include <openbsc/gsm_04_80.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/debug.h> +#include <openbsc/osmo_msc.h> + +/* Declarations of USSD strings to be recognised */ +const char USSD_TEXT_OWN_NUMBER[] = "*#100#"; + +/* Forward declarations of network-specific handler functions */ +static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req); +static int change_ss_activation(struct gsm_subscriber_connection *conn, uint8_t activate, const struct ss_request *req); +static int interrogate_ss(struct gsm_subscriber_connection *conn, const struct ss_request *req); + +/* Entrypoint - handler function common to all mobile-originated SS */ +int handle_rcv_ss(struct gsm_subscriber_connection *conn, struct msgb *msg) +{ + int rc; + struct ss_request req; + struct gsm48_hdr *gh; + uint8_t activate; + + memset(&req, 0, sizeof(req)); + gh = msgb_l3(msg); + rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req); + + if (rc == 1) { + + switch (req.opcode) { + case GSM0480_OP_CODE_PROCESS_USS_REQ: + + if (req.ussd_text[0] == 0xFF) /* Release-Complete */ + return 0; + + if (!strcmp(USSD_TEXT_OWN_NUMBER, + (const char *)req.ussd_text)) { + DEBUGP(DMM, "USSD: Own number requested\n"); + rc = send_own_number(conn, msg, &req); + } else { + DEBUGP(DMM, "Unhandled USSD %s\n", req.ussd_text); + rc = gsm0480_send_ss_reject(conn, &req, + GSM_0480_PROBLEM_CODE_TAG_INVOKE, + GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION); + } + + break; + + case GSM0480_OP_CODE_ACTIVATE_SS: + case GSM0480_OP_CODE_DEACTIVATE_SS: + activate = (req.opcode == GSM0480_OP_CODE_ACTIVATE_SS); + rc = change_ss_activation(conn, activate, &req); + break; + case GSM0480_OP_CODE_INTERROGATE_SS: + rc = interrogate_ss(conn, &req); + break; + default: + DEBUGP(DMM, "Unhandled SS opcode %d\n", req.opcode); + rc = gsm0480_send_ss_reject(conn, &req, + GSM_0480_PROBLEM_CODE_TAG_GENERAL, + GSM_0480_GEN_PROB_CODE_UNRECOGNISED); + break; + } + + } else { + rc = gsm0480_send_ss_reject(conn, &req, + GSM_0480_PROBLEM_CODE_TAG_GENERAL, + GSM_0480_GEN_PROB_CODE_BAD_STRUCTURE); + } + + /* check if we can release it */ + msc_release_connection(conn); + return rc; +} + +/* A network-specific handler function */ +static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req) +{ + char *own_number = conn->subscr->extension; + char response_string[GSM_EXTENSION_LENGTH + 20]; + + /* Need trailing CR as EOT character */ + snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number); + return gsm0480_send_ussd_response(conn, response_string, req); +} + +static int change_ss_activation(struct gsm_subscriber_connection *conn, uint8_t activate, const struct ss_request *req) +{ + struct msgb *msg; + uint8_t ss_status; + int rc = db_ss_interrogate_status(conn->subscr, + req->ss_code, + GSM0902_TS_CODE_TELEPHONY, + &ss_status); + + if(rc < 0 || !(ss_status & GSM0902_SS_STATUS_P_BIT)) { + DEBUGP(DMM, "SS 0x%02X not provisioned\n", req->ss_code); + return gsm0480_send_ss_reject(conn, req, + GSM_0480_PROBLEM_CODE_TAG_INVOKE, + GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION); + } + + ss_status &= ~GSM0902_SS_STATUS_A_BIT; + ss_status |= (activate ? GSM0902_SS_STATUS_A_BIT : 0); + + rc = db_ss_set_status(conn->subscr, req->ss_code, + GSM0902_TS_CODE_TELEPHONY, ss_status); + if(rc < 0) + return gsm0480_send_ss_reject(conn, req, + GSM_0480_PROBLEM_CODE_TAG_INVOKE, + GSM_0480_INVOKE_PROB_CODE_RESOURCE_LIMITATION); + + msg = gsm48_msgb_alloc(); + /* First put the payload into the message */ + msgb_push_TLV1(msg, GSM0902_SS_DATA_SS_STATUS_TAG, ss_status); + /* Then wrap it as a Sequence of type SS-Data */ + msgb_wrap_with_TL(msg, GSM0902_SS_INFO_SS_DATA_TAG); + + return gsm0480_send_ss_return_result(conn, req, msg); +} + +static int interrogate_ss(struct gsm_subscriber_connection *conn, const struct ss_request *req) +{ + struct msgb *msg; + uint8_t ss_status; + int rc = db_ss_interrogate_status(conn->subscr, + req->ss_code, + GSM0902_TS_CODE_TELEPHONY, + &ss_status); + + if(rc < 0 || !(ss_status & GSM0902_SS_STATUS_P_BIT)) { + DEBUGP(DMM, "SS 0x%02X not provisioned\n", req->ss_code); + return gsm0480_send_ss_reject(conn, req, + GSM_0480_PROBLEM_CODE_TAG_INVOKE, + GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION); + } + + msg = gsm48_msgb_alloc(); + /* Put the payload into the message */ + msgb_push_TLV1(msg, GSM0902_SS_INTERR_SS_RES_SS_STATUS_TAG, ss_status); + + return gsm0480_send_ss_return_result(conn, req, msg); +} diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c deleted file mode 100644 index 7f01eae..0000000 --- a/openbsc/src/libmsc/ussd.c +++ /dev/null @@ -1,87 +0,0 @@ -/* Network-specific handling of mobile-originated USSDs. */ - -/* (C) 2008-2009 by Harald Welte laforge@gnumonks.org - * (C) 2008, 2009 by Holger Hans Peter Freyther zecke@selfish.org - * (C) 2009 by Mike Haben michael.haben@btinternet.com - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -/* This module defines the network-specific handling of mobile-originated - USSD messages. */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include <openbsc/gsm_04_80.h> -#include <openbsc/gsm_subscriber.h> -#include <openbsc/debug.h> -#include <openbsc/osmo_msc.h> - -/* Declarations of USSD strings to be recognised */ -const char USSD_TEXT_OWN_NUMBER[] = "*#100#"; - -/* Forward declarations of network-specific handler functions */ -static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req); - - -/* Entrypoint - handler function common to all mobile-originated USSDs */ -int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg) -{ - int rc; - struct ussd_request req; - struct gsm48_hdr *gh; - - memset(&req, 0, sizeof(req)); - gh = msgb_l3(msg); - rc = gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req); - if (!rc) { - DEBUGP(DMM, "Unhandled SS\n"); - rc = gsm0480_send_ussd_reject(conn, msg, &req); - msc_release_connection(conn); - return rc; - } - - /* Release-Complete */ - if (req.text[0] == '\0') - return 0; - - if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.text)) { - DEBUGP(DMM, "USSD: Own number requested\n"); - rc = send_own_number(conn, msg, &req); - } else { - DEBUGP(DMM, "Unhandled USSD %s\n", req.text); - rc = gsm0480_send_ussd_reject(conn, msg, &req); - } - - /* check if we can release it */ - msc_release_connection(conn); - return rc; -} - -/* A network-specific handler function */ -static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req) -{ - char *own_number = conn->subscr->extension; - char response_string[GSM_EXTENSION_LENGTH + 20]; - - /* Need trailing CR as EOT character */ - snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number); - return gsm0480_send_ussd_response(conn, msg, response_string, req); -}
Signed-off-by: Max max.suraev@fairwaves.co --- openbsc/include/openbsc/gsm_subscriber.h | 1 + openbsc/src/libmsc/gsm_04_08.c | 39 +++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 7d6c776..6b2a88a 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -65,6 +65,7 @@ struct gsm_subscriber {
/* for internal management */ int use_count; + int active_cc_transactions; struct llist_head entry;
/* pending requests */ diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 01f8f32..127d5f4 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -1261,9 +1261,19 @@ static void new_cc_state(struct gsm_trans *trans, int state) if (state > 31 || state < 0) return;
- DEBUGP(DCC, "new state %s -> %s\n", - gsm48_cc_state_name(trans->cc.state), - gsm48_cc_state_name(state)); + if (trans->subscr) { + if (state != GSM_CSTATE_NULL && + trans->cc.state == GSM_CSTATE_NULL) + trans->subscr->active_cc_transactions++; + else if(state == GSM_CSTATE_NULL && + trans->cc.state != GSM_CSTATE_NULL) + trans->subscr->active_cc_transactions--; + } + + DEBUGP(DCC, "new state %s -> %s, %d active transactions\n", + gsm48_cc_state_name(trans->cc.state), + gsm48_cc_state_name(state), + trans->subscr->active_cc_transactions);
trans->cc.state = state; } @@ -3063,6 +3073,29 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_DEST_OOO); } + /* If subscriber is "busy" */ + if (subscr->active_cc_transactions) { + int rc; + uint8_t ss_status = 0; + rc = db_ss_interrogate_status(subscr, + GSM0902_SS_CODE_CW, + GSM0902_TS_CODE_TELEPHONY, + &ss_status); + DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " + "Received '%s' from MNCC with " + "busy subscriber %s, cw ss_status: %X\n", + data->called.number, get_mncc_name(msg_type), + data->called.number, ss_status); + if(rc < 0 || (ss_status != (GSM0902_SS_STATUS_P_BIT | + GSM0902_SS_STATUS_A_BIT))) { + subscr_put(subscr); + /* User busy */ + return mncc_release_ind(net, NULL, + data->callref, + GSM48_CAUSE_LOC_USER, + GSM48_CC_CAUSE_USER_BUSY); + } + } /* Create transaction */ trans = trans_alloc(net, subscr, GSM48_PDISC_CC, 0xff, data->callref); if (!trans) {
Signed-off-by: Max max.suraev@fairwaves.co --- openbsc/include/openbsc/gsm_04_80.h | 4 ++++ openbsc/src/libmsc/gsm_04_80.c | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index 7139f95..20ec3ab 100644 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -39,6 +39,10 @@ int gsm0480_send_ss_reject(struct gsm_subscriber_connection *conn, const struct ss_request *request, uint8_t problem_category, uint8_t problem_code); +int gsm0480_send_ss_return_error(struct gsm_subscriber_connection *conn, + const struct ss_request *req, + uint8_t error_code, + struct msgb *parameters);
int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text); int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn); diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c index b20521a..82b5623 100644 --- a/openbsc/src/libmsc/gsm_04_80.c +++ b/openbsc/src/libmsc/gsm_04_80.c @@ -91,8 +91,8 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
/* Send response to a mobile-originated Invoke */ int gsm0480_send_ss_return_result(struct gsm_subscriber_connection *conn, - const struct ss_request *req, - struct msgb *msg) + const struct ss_request *req, + struct msgb *msg) { struct gsm48_hdr *gh;
@@ -149,6 +149,38 @@ int gsm0480_send_ss_reject(struct gsm_subscriber_connection *conn, return gsm0808_submit_dtap(conn, msg, 0, 0); }
+int gsm0480_send_ss_return_error(struct gsm_subscriber_connection *conn, + const struct ss_request *req, + uint8_t error_code, + struct msgb *parameters) +{ + struct msgb *msg = parameters; + struct gsm48_hdr *gh; + + if(!msg) + msg = gsm48_msgb_alloc(); + + /* Pre-pend the error code */ + msgb_push_TLV1(msg, GSM_0480_ERROR_CODE_TAG, error_code); + + /* Before it insert the invoke ID */ + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); + + /* Wrap this up as a Reject component */ + msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_ERROR); + + /* Wrap the component in a Facility message */ + msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); + + /* And finally pre-pend the L3 header */ + gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_NC_SS; + gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */ + gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; + + return gsm0808_submit_dtap(conn, msg, 0, 0); +} + int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text) { struct gsm48_hdr *gh;
Signed-off-by: Max max.suraev@fairwaves.co --- openbsc/src/libmsc/ss.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/openbsc/src/libmsc/ss.c b/openbsc/src/libmsc/ss.c index 44a01ec..4eabe1a 100644 --- a/openbsc/src/libmsc/ss.c +++ b/openbsc/src/libmsc/ss.c @@ -125,9 +125,9 @@ static int change_ss_activation(struct gsm_subscriber_connection *conn, uint8_t
if(rc < 0 || !(ss_status & GSM0902_SS_STATUS_P_BIT)) { DEBUGP(DMM, "SS 0x%02X not provisioned\n", req->ss_code); - return gsm0480_send_ss_reject(conn, req, - GSM_0480_PROBLEM_CODE_TAG_INVOKE, - GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION); + return gsm0480_send_ss_return_error(conn, req, + GSM0480_ERR_CODE_SS_SUBSCRIPTION_VIOLATION, + NULL); }
ss_status &= ~GSM0902_SS_STATUS_A_BIT; @@ -160,9 +160,9 @@ static int interrogate_ss(struct gsm_subscriber_connection *conn, const struct s
if(rc < 0 || !(ss_status & GSM0902_SS_STATUS_P_BIT)) { DEBUGP(DMM, "SS 0x%02X not provisioned\n", req->ss_code); - return gsm0480_send_ss_reject(conn, req, - GSM_0480_PROBLEM_CODE_TAG_INVOKE, - GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION); + return gsm0480_send_ss_return_error(conn, req, + GSM0480_ERR_CODE_SS_SUBSCRIPTION_VIOLATION, + NULL); }
msg = gsm48_msgb_alloc();