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 | 19 +++- openbsc/src/gsm_04_80.c | 252 +++++++++++++++++++++-------------- openbsc/src/ussd.c | 15 ++- 3 files changed, 180 insertions(+), 106 deletions(-) mode change 100644 => 100755 openbsc/include/openbsc/ussd.h mode change 100644 => 100755 openbsc/src/gsm_04_08.c mode change 100644 => 100755 openbsc/src/ussd.c diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index d16a876..43b5b74 100755 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -3,8 +3,25 @@ #include <openbsc/msgb.h> +/* GSM TS 04.80 definitions (Supplementary Services specification, Formats and coding */ +/* Section 3.6.5 */ +#define GSM_0480_SEQUENCE_TAG 0x30 +#define GSM_0480_SET_TAG 0x31 + +/* ASN.1 type-tags */ +#define ASN1_BOOLEAN_TAG 0x01 +#define ASN1_INTEGER_TAG 0x02 +#define ASN1_BIT_STRING_TAG 0x03 +#define ASN1_OCTET_STRING_TAG 0x04 +#define ASN1_NULL_TYPE_TAG 0x05 +#define ASN1_OBJECT_ID_TAG 0x06 +#define ASN1_UTF8_STRING_TAG 0x0C +#define ASN1_PRINTABLE_STRING_TAG 0x13 +#define ASN1_IA5_STRING_TAG 0x16 +#define ASN1_UNICODE_STRING_TAG 0x1E + 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); +int gsm0480_send_ussd_reject(struct msgb *msg); #endif diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h old mode 100644 new mode 100755 diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c old mode 100644 new mode 100755 diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c index c2c2a86..a6dffa8 100755 --- a/openbsc/src/gsm_04_80.c +++ b/openbsc/src/gsm_04_80.c @@ -39,26 +39,63 @@ /* 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 +#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 +#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 +#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 +#define GSM0480_COMPIDTAG_INVOKE_ID 0x02 +#define GSM0480_COMPIDTAG_LINKED_ID 0x80 /* Section 3.6.4 */ -#define GSM0480_OPERATION_CODE 0x02 +#define GSM0480_OPERATION_CODE 0x02 + +/* Section 3.6.6 */ +#define GSM_0480_ERROR_CODE_TAG 0x02 + +/* Section 3.6.7 */ +/* Table 3.13 */ +#define GSM_0480_PROBLEM_CODE_TAG_GENERAL 0x80 +#define GSM_0480_PROBLEM_CODE_TAG_INVOKE 0x81 +#define GSM_0480_PROBLEM_CODE_TAG_RETURN_RESULT 0x82 +#define GSM_0480_PROBLEM_CODE_TAG_RETURN_ERROR 0x83 + +/* Table 3.14 */ +#define GSM_0480_GEN_PROB_CODE_UNRECOGNISED 0x00 +#define GSM_0480_GEN_PROB_CODE_MISTYPED 0x01 +#define GSM_0480_GEN_PROB_CODE_BAD_STRUCTURE 0x02 + +/* Table 3.15 */ +#define GSM_0480_INVOKE_PROB_CODE_DUPLICATE_INVOKE_ID 0x00 +#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION 0x01 +#define GSM_0480_INVOKE_PROB_CODE_MISTYPED_PARAMETER 0x02 +#define GSM_0480_INVOKE_PROB_CODE_RESOURCE_LIMITATION 0x03 +#define GSM_0480_INVOKE_PROB_CODE_INITIATING_RELEASE 0x04 +#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_LINKED_ID 0x05 +#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_RESPONSE 0x06 +#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_OPERATION 0x07 + +/* Table 3.16 */ +#define GSM_0480_RESULT_PROB_CODE_UNRECOGNISED_INVOKE_ID 0x00 +#define GSM_0480_RESULT_PROB_CODE_RETURN_RESULT_UNEXPECTED 0x01 +#define GSM_0480_RESULT_PROB_CODE_MISTYPED_PARAMETER 0x02 + +/* Table 3.17 */ +#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_INVOKE_ID 0x00 +#define GSM_0480_ERROR_PROB_CODE_RETURN_ERROR_UNEXPECTED 0x01 +#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_ERROR 0x02 +#define GSM_0480_ERROR_PROB_CODE_UNEXPECTED_ERROR 0x03 +#define GSM_0480_ERROR_PROB_CODE_MISTYPED_PARAMETER 0x04 /* Section 4.5 */ #define GSM0480_OP_CODE_REGISTER_SS 0x0A @@ -105,11 +142,13 @@ #define GSM0480_ERR_CODE_MAX_MPTY_PARTICIPANTS 0x7E #define GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE 0x7F -static char ussd_string_buff[256]; +static char ussd_string_buff[32]; +static u_int8_t last_transaction_id; +static u_int8_t last_invoke_id; /* 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_ussd(u_int8_t *ussd); +static int parse_ussd_information_elements(u_int8_t *ussd_ie); 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); @@ -117,34 +156,26 @@ 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 + int rc = 0; + u_int8_t* parse_ptr = msgb_l3(msg); - DEBUGP(DMM, "USSD %s\n", hexdump(msg->data, msg->len)); // preliminary! Just see what we're receiving... +// DEBUGP(DMM, "USSD %s\n", hexdump(msg->data, msg->len)); // temporary, just see what we're receiving... memset(ussd_string_buff, 0, sizeof(ussd_string_buff)); - do + if((*parse_ptr & 0x0F) == GSM48_PDISC_NC_SS) { - 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); + last_transaction_id = *parse_ptr & 0xF0; + rc = parse_ussd(parse_ptr + 1); } - while(offset < msg->len); - if(rc) - DEBUGP(DMM, "USSD received OK, response not yet implemented\n"); - else + if(!rc) 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) +static int parse_ussd(u_int8_t *ussd) { int rc = 1; u_int8_t msg_type = ussd[0] & 0xBF; // message-type - section 3.4 @@ -152,10 +183,11 @@ static int parse_ussd(u_int8_t *ussd, u_int8_t length) switch(msg_type) { case GSM0480_MTYPE_RELEASE_COMPLETE: DEBUGP(DMM, "USS Release Complete\n"); // could also parse out the optional Cause/Facility data + ussd_string_buff[0] = 0xFF; break; case GSM0480_MTYPE_REGISTER: case GSM0480_MTYPE_FACILITY: - rc &= parse_ussd_information_elements(ussd+1, length-1); + rc &= parse_ussd_information_elements(ussd+1); break; default: fprintf(stderr, "Unknown GSM 04.80 message-type field 0x%02x\n", @@ -167,34 +199,26 @@ static int parse_ussd(u_int8_t *ussd, u_int8_t length) return rc; } -static int parse_ussd_information_elements(u_int8_t *ussd_ie, u_int8_t length) +static int parse_ussd_information_elements(u_int8_t *ussd_ie) { - int rc = 1; - u_int8_t offset = 0; + int rc; - 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); + u_int8_t iei = ussd_ie[0]; // Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 + u_int8_t iei_length = ussd_ie[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; } - while(offset < length); return rc; } @@ -243,6 +267,7 @@ static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) invoke_data[0]); } u_int8_t offset = invoke_data[1] + 2; + last_invoke_id = invoke_data[2]; if(invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID) // optional part offset += invoke_data[offset+1] + 2; // skip over it @@ -252,7 +277,7 @@ static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) 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); + rc = parse_process_uss_req(invoke_data + offset + 3, length - offset - 3); break; default: fprintf(stderr, "GSM 04.80 operation code 0x%02x is not yet handled\n", @@ -275,75 +300,100 @@ 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) { int rc = 1; + int num_chars; 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); +// DEBUGP(DMM, "USSD request params %s\n", hexdump(uss_req_data, length)); + /* FIXME: most phones send USSD text as a 7-bit encoded octet string; the following code + also handles the case of plain ASCII text (IA5String), but other encodings might be used */ + if(uss_req_data[0] == GSM_0480_SEQUENCE_TAG) + { + if(uss_req_data[2] == ASN1_OCTET_STRING_TAG) + { + dcs = uss_req_data[4]; +// DEBUGP(DMM, "Data coding scheme = 0x%2.2X\n", dcs); + if((dcs == 0x0F) && (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) + { + num_chars = (uss_req_data[6] * 8) / 7; + gsm_7bit_decode(ussd_string_buff, &(uss_req_data[7]), num_chars); + } + } + } + else if(uss_req_data[0] == ASN1_IA5_STRING_TAG) + { + num_chars = uss_req_data[1]; + memcpy(ussd_string_buff, &(uss_req_data[2]), num_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; + int response_len; + response_len = strlen(response_text); + + msg->bts_link = in_msg->bts_link; 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); + gh->proto_discr = GSM48_PDISC_NC_SS | last_transaction_id | 0x80; // TI direction = 1 + gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; + + ptr8 = msgb_put(msg, 14); ptr8[0] = GSM0480_IE_FACILITY; - ptr8[1] = response_len + 17; + ptr8[1] = response_len + 12; ptr8[2] = GSM0480_CTYPE_RETURN_RESULT; - ptr8[3] = response_len + 15; + ptr8[3] = response_len + 10; 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[6] = last_invoke_id; + ptr8[7] = GSM_0480_SEQUENCE_TAG; + ptr8[8] = response_len + 5; 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[11] = GSM0480_OP_CODE_PROCESS_USS_DATA; + ptr8[12] = ASN1_IA5_STRING_TAG; + ptr8[13] = response_len; ptr8 = msgb_put(msg, response_len); - gsm_7bit_encode(ptr8, response_text); + memcpy(ptr8, response_text, response_len); - DEBUGP(DMM, "USSD response %s\n", hexdump(msg->data, msg->len)); // preliminary! Just see what we're sending... +// DEBUGP(DMM, "USSD response %s\n", hexdump(msg->data, msg->len)); // temporary, just to see what we're sending back - return -EINVAL; /* Temporary */ -// return gsm48_sendmsg(msg, NULL); + return gsm48_sendmsg(msg, NULL); } -/* !!! Not yet complete or even partly working */ -int gsm0480_send_ussd_error(struct msgb *in_msg) +int gsm0480_send_ussd_reject(struct msgb *in_msg) { - return -EINVAL; + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + u_int8_t *ptr8; + + msg->bts_link = in_msg->bts_link; + msg->lchan = in_msg->lchan; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_NC_SS | last_transaction_id | 0x80; // TI direction = 1 + gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; + + ptr8 = msgb_put(msg, 10); + ptr8[0] = GSM0480_IE_FACILITY; + ptr8[1] = 8; + ptr8[2] = GSM0480_CTYPE_REJECT; + ptr8[3] = 6; + ptr8[4] = GSM0480_COMPIDTAG_INVOKE_ID; + ptr8[5] = 1; + ptr8[6] = last_invoke_id; + ptr8[7] = GSM_0480_PROBLEM_CODE_TAG_GENERAL; + ptr8[8] = 1; + ptr8[9] = GSM_0480_GEN_PROB_CODE_UNRECOGNISED; + +// DEBUGP(DMM, "USSD reject %s\n", hexdump(msg->data, msg->len)); // temporary, just to see what we're sending back + + return gsm48_sendmsg(msg, NULL); } diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c old mode 100644 new mode 100755 index 26b4686..761a0e7 --- a/openbsc/src/ussd.c +++ b/openbsc/src/ussd.c @@ -1,4 +1,4 @@ -/* Handler for mobile-originated USSDs */ +/* Network-specific handling of 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> @@ -31,13 +31,17 @@ #include <openbsc/gsm_subscriber.h> #include <openbsc/debug.h> -#define USSD_TEXT_OWN_NUMBER "*#100#" +const char 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); + + if(ussd_text_rcvd[0] == 0xFF) // Release-Complete + return 0; + 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) @@ -48,12 +52,15 @@ int handle_rcv_ussd(struct msgb *msg) else { DEBUGP(DMM, "Unhandled USSD %s\n", ussd_text_rcvd); - return gsm0480_send_ussd_error(msg); + return gsm0480_send_ussd_reject(msg); } } static int send_own_number(struct msgb *msg) { + char response_string[] = "Your extension is xxxxx"; + char* own_number = msg->lchan->subscr->extension; - return gsm0480_send_ussd_response(msg, own_number); + memcpy(response_string + 18, own_number, 5); + return gsm0480_send_ussd_response(msg, response_string); } -- 1.6.0.4 --------------040900030502000202050609--