From patchwork Thu Jul 9 19:02:21 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max X-Patchwork-Id: 493524 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.osmocom.org (tmp.osmocom.org [144.76.43.76]) by ozlabs.org (Postfix) with ESMTP id 9A39F140B0D for ; Fri, 10 Jul 2015 05:12:58 +1000 (AEST) Received: from lists.osmocom.org (lists.osmocom.org [144.76.43.76]) by lists.osmocom.org (Postfix) with ESMTP id 6E597764D; Thu, 9 Jul 2015 19:12:57 +0000 (UTC) X-Original-To: openbsc@lists.osmocom.org Delivered-To: openbsc@lists.osmocom.org Received: from hylle06.itea.ntnu.no (hylle06.itea.ntnu.no [129.241.56.235]) by lists.osmocom.org (Postfix) with ESMTP id B543E7634 for ; Thu, 9 Jul 2015 19:12:56 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hylle06.itea.ntnu.no (Postfix) with ESMTP id ED9B4662D28 for ; Thu, 9 Jul 2015 21:02:58 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at hylle06.itea.ntnu.no Received: from alumnimail01.it.ntnu.no (alumnimail01.it.ntnu.no [129.241.18.54]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hylle06.itea.ntnu.no (Postfix) with ESMTPS id B94846626DB for ; Thu, 9 Jul 2015 21:02:56 +0200 (CEST) Received: from localhost (dslb-094-223-143-244.094.223.pools.vodafone-ip.de [94.223.143.244]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) (Authenticated sender: suraev) by alumnimail01.it.ntnu.no (Postfix) with ESMTPSA id D167955260 for ; Thu, 9 Jul 2015 21:02:55 +0200 (CEST) From: Max To: openbsc@lists.osmocom.org Subject: [PATCH 1/4] Supplementary Services (de)activation and interrogation Date: Thu, 9 Jul 2015 21:02:21 +0200 Message-Id: <1436468544-20989-1-git-send-email-max.suraev@fairwaves.co> X-Mailer: git-send-email 2.1.4 X-BeenThere: openbsc@lists.osmocom.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Development of the OpenBSC GSM base station controller List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openbsc-bounces@lists.osmocom.org Sender: "OpenBSC" Signed-off-by: Max --- 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 #include +#include #include 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 + +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 - -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 + 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 #include #include -#include +#include #include #include #include @@ -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 #include -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 + * (C) 2008, 2009 by Holger Hans Peter Freyther + * (C) 2009 by Mike Haben + * + * 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 . + * + */ + +/* This module defines the network-specific handling of mobile-originated + SS messages. */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* 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 - * (C) 2008, 2009 by Holger Hans Peter Freyther - * (C) 2009 by Mike Haben - * - * 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 . - * - */ - -/* This module defines the network-specific handling of mobile-originated - USSD messages. */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -/* 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); -}