This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.
Mike Haben michael.haben at btinternet.com--- openbsc/include/openbsc/gsm_04_80.h | 10 + openbsc/include/openbsc/ussd.h | 8 + openbsc/src/Makefile.am | 2 +- openbsc/src/gsm_04_08.c | 6 +- openbsc/src/gsm_04_80.c | 349 +++++++++++++++++++++++++++++++++++ openbsc/src/ussd.c | 59 ++++++ 6 files changed, 431 insertions(+), 3 deletions(-) create mode 100755 openbsc/include/openbsc/gsm_04_80.h create mode 100644 openbsc/include/openbsc/ussd.h create mode 100755 openbsc/src/gsm_04_80.c create mode 100644 openbsc/src/ussd.c diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h new file mode 100755 index 0000000..d16a876 --- /dev/null +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -0,0 +1,10 @@ +#ifndef _GSM_04_80_H +#define _GSM_04_80_H + +#include <openbsc/msgb.h> + +char* gsm0480_rcv_ussd(struct msgb *msg); +int gsm0480_send_ussd_response(struct msgb *msg, const char* response_text); +int gsm0480_send_ussd_error(struct msgb *msg); + +#endif diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h new file mode 100644 index 0000000..dfd34f3 --- /dev/null +++ b/openbsc/include/openbsc/ussd.h @@ -0,0 +1,8 @@ +#ifndef _USSD_H +#define _USSD_H + +#include <openbsc/msgb.h> + +int handle_rcv_ussd(struct msgb *msg); + +#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 919e075..2f715bb 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -14,7 +14,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ - token_auth.c rrlp.c + token_auth.c rrlp.c gsm_04_80.c ussd.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 9ad9e15..62f2c18 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -48,6 +48,7 @@ #include <openbsc/rtp_proxy.h> #include <openbsc/talloc.h> #include <openbsc/transaction.h> +#include <openbsc/ussd.h> #define GSM_MAX_FACILITY 128 #define GSM_MAX_SSVERSION 128 @@ -3544,7 +3545,6 @@ static int gsm0408_rcv_cc(struct msgb *msg) return rc; } -/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -3566,10 +3566,12 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id) break; case GSM48_PDISC_MM_GPRS: case GSM48_PDISC_SM_GPRS: - case GSM48_PDISC_NC_SS: /* mobile-originated USSD */ fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02x\n", pdisc); break; + case GSM48_PDISC_NC_SS: + rc = handle_rcv_ussd(msg); + break; default: fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02x\n", pdisc); diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c new file mode 100755 index 0000000..c2c2a86 --- /dev/null +++ b/openbsc/src/gsm_04_80.c @@ -0,0 +1,349 @@ +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (C) 2008-2009 by Harald Welte <laforge at gnumonks.org> + * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke at selfish.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <openbsc/msgb.h> +#include <openbsc/tlv.h> +#include <openbsc/debug.h> +#include <openbsc/gsm_data.h> +#include <openbsc/gsm_utils.h> +#include <openbsc/gsm_04_08.h> +#include <openbsc/gsm_04_80.h> + +/* GSM TS 04.80 definitions (Supplementary Services specification, Formats and coding */ + +/* Section 3.4 */ +#define GSM0480_MTYPE_RELEASE_COMPLETE 0x2A +#define GSM0480_MTYPE_FACILITY 0x3A +#define GSM0480_MTYPE_REGISTER 0x3B + +/* Section 3.5 */ +#define GSM0480_IE_FACILITY 0x1C +#define GSM0480_IE_SS_VERSION 0x7F + +/* Section 3.6.2 */ +#define GSM0480_CTYPE_INVOKE 0xA1 +#define GSM0480_CTYPE_RETURN_RESULT 0xA2 +#define GSM0480_CTYPE_RETURN_ERROR 0xA3 +#define GSM0480_CTYPE_REJECT 0xA4 + +/* Section 3.6.3 */ +#define GSM0480_COMPIDTAG_INVOKE_ID 0x02 +#define GSM0480_COMPIDTAG_LINKED_ID 0x80 + +/* Section 3.6.4 */ +#define GSM0480_OPERATION_CODE 0x02 + +/* Section 4.5 */ +#define GSM0480_OP_CODE_REGISTER_SS 0x0A +#define GSM0480_OP_CODE_ERASE_SS 0x0B +#define GSM0480_OP_CODE_ACTIVATE_SS 0x0C +#define GSM0480_OP_CODE_DEACTIVATE_SS 0x0D +#define GSM0480_OP_CODE_INTERROGATE_SS 0x0E +#define GSM0480_OP_CODE_NOTIFY_SS 0x10 +#define GSM0480_OP_CODE_REGISTER_PASSWORD 0x11 +#define GSM0480_OP_CODE_GET_PASSWORD 0x12 +#define GSM0480_OP_CODE_PROCESS_USS_DATA 0x13 +#define GSM0480_OP_CODE_FORWARD_CHECK_SS_IND 0x26 +#define GSM0480_OP_CODE_PROCESS_USS_REQ 0x3B +#define GSM0480_OP_CODE_USS_REQUEST 0x3C +#define GSM0480_OP_CODE_USS_NOTIFY 0x3D +#define GSM0480_OP_CODE_FORWARD_CUG_INFO 0x78 +#define GSM0480_OP_CODE_SPLIT_MPTY 0x79 +#define GSM0480_OP_CODE_RETRIEVE_MPTY 0x7A +#define GSM0480_OP_CODE_HOLD_MPTY 0x7B +#define GSM0480_OP_CODE_BUILD_MPTY 0x7C +#define GSM0480_OP_CODE_FORWARD_CHARGE_ADVICE 0x7D + +#define GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER 0x01 +#define GSM0480_ERR_CODE_ILLEGAL_SUBSCRIBER 0x09 +#define GSM0480_ERR_CODE_BEARER_SERVICE_NOT_PROVISIONED 0x0A +#define GSM0480_ERR_CODE_TELESERVICE_NOT_PROVISIONED 0x0B +#define GSM0480_ERR_CODE_ILLEGAL_EQUIPMENT 0x0C +#define GSM0480_ERR_CODE_CALL_BARRED 0x0D +#define GSM0480_ERR_CODE_ILLEGAL_SS_OPERATION 0x10 +#define GSM0480_ERR_CODE_SS_ERROR_STATUS 0x11 +#define GSM0480_ERR_CODE_SS_NOT_AVAILABLE 0x12 +#define GSM0480_ERR_CODE_SS_SUBSCRIPTION_VIOLATION 0x13 +#define GSM0480_ERR_CODE_SS_INCOMPATIBILITY 0x14 +#define GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED 0x15 +#define GSM0480_ERR_CODE_ABSENT_SUBSCRIBER 0x1B +#define GSM0480_ERR_CODE_SYSTEM_FAILURE 0x22 +#define GSM0480_ERR_CODE_DATA_MISSING 0x23 +#define GSM0480_ERR_CODE_UNEXPECTED_DATA_VALUE 0x24 +#define GSM0480_ERR_CODE_PW_REGISTRATION_FAILURE 0x25 +#define GSM0480_ERR_CODE_NEGATIVE_PW_CHECK 0x26 +#define GSM0480_ERR_CODE_NUM_PW_ATTEMPTS_VIOLATION 0x2B +#define GSM0480_ERR_CODE_UNKNOWN_ALPHABET 0x47 +#define GSM0480_ERR_CODE_USSD_BUSY 0x48 +#define GSM0480_ERR_CODE_MAX_MPTY_PARTICIPANTS 0x7E +#define GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE 0x7F + +static char ussd_string_buff[256]; + +/* Forward declarations */ +static int parse_ussd(u_int8_t *ussd, u_int8_t length); +static int parse_ussd_information_elements(u_int8_t *ussd_ie, u_int8_t length); +static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length); +static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length); +static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length); + +/* Receive a mobile-originated USSD message and return the decoded text */ +char* gsm0480_rcv_ussd(struct msgb *msg) +{ + int rc = 1; + u_int8_t tag; + u_int8_t length; + u_int8_t offset = 2; // don't yet understand the first 2 bytes, so ignore them for now + + DEBUGP(DMM, "USSD %s\n", hexdump(msg->data, msg->len)); // preliminary! Just see what we're receiving... + + memset(ussd_string_buff, 0, sizeof(ussd_string_buff)); + + do + { + tag = msg->data[offset]; + length = msg->data[offset+1]; + if((msg->data[offset+2] & 0x0f) == GSM48_PDISC_NC_SS) // not sure if this is correct??? + rc &= parse_ussd(&(msg->data[offset+3]), length-3); + offset += (length+2); + } + while(offset < msg->len); + + if(rc) + DEBUGP(DMM, "USSD received OK, response not yet implemented\n"); + else + DEBUGP(DMM, "Error occurred while parsing received USSD!\n"); + + return ussd_string_buff; +} + +static int parse_ussd(u_int8_t *ussd, u_int8_t length) +{ + int rc = 1; + u_int8_t msg_type = ussd[0] & 0xBF; // message-type - section 3.4 + + switch(msg_type) { + case GSM0480_MTYPE_RELEASE_COMPLETE: + DEBUGP(DMM, "USS Release Complete\n"); // could also parse out the optional Cause/Facility data + break; + case GSM0480_MTYPE_REGISTER: + case GSM0480_MTYPE_FACILITY: + rc &= parse_ussd_information_elements(ussd+1, length-1); + break; + default: + fprintf(stderr, "Unknown GSM 04.80 message-type field 0x%02x\n", + ussd[0]); + rc = 0; + break; + } + + return rc; +} + +static int parse_ussd_information_elements(u_int8_t *ussd_ie, u_int8_t length) +{ + int rc = 1; + u_int8_t offset = 0; + + do + { + u_int8_t iei = ussd_ie[offset]; // Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 + u_int8_t iei_length = ussd_ie[offset+1]; + switch(iei) { + case GSM48_IE_CAUSE: + break; + case GSM0480_IE_FACILITY: + rc &= parse_facility_ie(ussd_ie+2, iei_length); + break; + case GSM0480_IE_SS_VERSION: + break; + default: + fprintf(stderr, "Unhandled GSM 04.08 or 04.80 Information Element Identifier 0x%02x\n", + iei); + rc = 0; + break; + } + + + offset += (iei_length+2); + } + while(offset < length); + + return rc; +} + +static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length) +{ + int rc = 1; + u_int8_t offset = 0; + + do + { + u_int8_t component_type = facility_ie[offset]; // Component Type tag - table 3.7 + u_int8_t component_length = facility_ie[offset+1]; + switch(component_type) { + case GSM0480_CTYPE_INVOKE: + rc &= parse_ss_invoke(facility_ie+2, component_length); + break; + case GSM0480_CTYPE_RETURN_RESULT: + break; + case GSM0480_CTYPE_RETURN_ERROR: + break; + case GSM0480_CTYPE_REJECT: + break; + default: + fprintf(stderr, "Unknown GSM 04.80 Facility Component Type 0x%02x\n", + component_type); + rc = 0; + break; + } + + offset += (component_length+2); + } + while(offset < length); + + return rc; +} + +/* Parse an Invoke component - see table 3.3 */ +static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) +{ + int rc = 1; + + if(invoke_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) // mandatory part + { + fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x (expecting Invoke ID tag)\n", + invoke_data[0]); + } + u_int8_t offset = invoke_data[1] + 2; + + if(invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID) // optional part + offset += invoke_data[offset+1] + 2; // skip over it + + if(invoke_data[offset] == GSM0480_OPERATION_CODE) // mandatory part + { + u_int8_t operation_code = invoke_data[offset+2]; + switch(operation_code) { + case GSM0480_OP_CODE_PROCESS_USS_REQ: + rc = parse_process_uss_req(invoke_data + 3, length - 3); + break; + default: + fprintf(stderr, "GSM 04.80 operation code 0x%02x is not yet handled\n", + operation_code); + rc = 0; + break; + } + } + else + { + fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x (expecting Operation Code tag)\n", + invoke_data[0]); + rc = 0; + } + + return rc; +} + +/* Parse the parameters of a Process UnstructuredSS Request */ +static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length) +{ + int rc = 1; + u_int8_t dcs; + + /* FIXME: properly parse out the initial tag and length, then the data-coding scheme and finally the text - + following piece of code uses hard-coded offsets into the data */ + dcs = uss_req_data[7]; + DEBUGP(DMM, "Data coding scheme = 0x%2.2X\n", dcs); // temporary + + int num_7_bit_chars = (uss_req_data[9] * 8) / 7; + gsm_7bit_decode(ussd_string_buff, &(uss_req_data[10]), num_7_bit_chars); + + return rc; +} + +/* !!! Not yet complete or even partly working, causes a test phone to reboot! */ +int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + struct gsm_network *net = in_msg->lchan->ts->trx->bts->network; + u_int8_t *ptr8; + int response_len, response_pad; + + msg->lchan = in_msg->lchan; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_NC_SS; + gh->msg_type = GSM0480_MTYPE_FACILITY; + +/* FIXME: Need to add lots of stuff here to build up a valid USSD - + GSM0480_IE_FACILITY, GSM0480_CTYPE_INVOKE(?), GSM0480_COMPIDTAG_INVOKE_ID, + GSM0480_OPERATION_CODE, GSM0480_OP_CODE_PROCESS_USS_REQ(?) */ + + response_len = (strlen(response_text)*7)/8; + response_pad = (8 - strlen(net->name_long)*7)%8; + if (response_pad > 0) + response_len++; + /* 10.5.3.5a */ + ptr8 = msgb_put(msg, 19); + ptr8[0] = GSM0480_IE_FACILITY; + ptr8[1] = response_len + 17; + ptr8[2] = GSM0480_CTYPE_RETURN_RESULT; + ptr8[3] = response_len + 15; + ptr8[4] = GSM0480_COMPIDTAG_INVOKE_ID; + ptr8[5] = 1; + ptr8[6] = 0x80; // invoke-ID -128 + ptr8[7] = 0x30; // don't yet understand where this comes from + ptr8[8] = response_len + 10; + ptr8[9] = GSM0480_OPERATION_CODE; + ptr8[10] = 1; + ptr8[11] = GSM0480_OP_CODE_PROCESS_USS_REQ; + ptr8[12] = 0x30; // don't yet understand where this comes from + ptr8[13] = response_len + 5; + ptr8[14] = 0x04; // indicates DCS to follow + ptr8[15] = 1; // length of DCS + ptr8[16] = 0x0F; // DCS + ptr8[17] = 0x04; // indicates string to follow + ptr8[18] = response_len; + + ptr8 = msgb_put(msg, response_len); + gsm_7bit_encode(ptr8, response_text); + + DEBUGP(DMM, "USSD response %s\n", hexdump(msg->data, msg->len)); // preliminary! Just see what we're sending... + + return -EINVAL; /* Temporary */ +// return gsm48_sendmsg(msg, NULL); +} + +/* !!! Not yet complete or even partly working */ +int gsm0480_send_ussd_error(struct msgb *in_msg) +{ + return -EINVAL; +} diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c new file mode 100644 index 0000000..26b4686 --- /dev/null +++ b/openbsc/src/ussd.c @@ -0,0 +1,59 @@ +/* Handler for mobile-originated USSDs */ + +/* (C) 2008-2009 by Harald Welte <laforge at gnumonks.org> + * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke at selfish.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#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> + +#define USSD_TEXT_OWN_NUMBER "*#100#" + +static int send_own_number(struct msgb *msg); + +int handle_rcv_ussd(struct msgb *msg) +{ + char* ussd_text_rcvd = gsm0480_rcv_ussd(msg); + DEBUGP(DMM, "Received USSD text %s\n", ussd_text_rcvd); // show text payload entered on MS + + if(strstr(USSD_TEXT_OWN_NUMBER, ussd_text_rcvd) != NULL) + { + DEBUGP(DMM, "USSD: Own number requested\n"); + return send_own_number(msg); + } + else + { + DEBUGP(DMM, "Unhandled USSD %s\n", ussd_text_rcvd); + return gsm0480_send_ussd_error(msg); + } +} + +static int send_own_number(struct msgb *msg) +{ + char* own_number = msg->lchan->subscr->extension; + return gsm0480_send_ussd_response(msg, own_number); +} -- 1.6.0.4 --------------040900030502000202050609 Content-Type: text/x-diff; name="0002-Support-for-mobile-originated-USSD-working-demonst.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename*0="0002-Support-for-mobile-originated-USSD-working-demonst.patc"; filename*1="h"