---
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(a)gnumonks.org>
* (C) 2008, 2009 by Holger Hans Peter Freyther <zecke(a)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--