[PATCH 3/4] core: Modify ss_request struct to store all information about USSD session

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/.

Sergey.Kostanbaev sergey.kostanbaev at gmail.com
Wed Nov 25 10:37:03 UTC 2015


From: Sergey Kostanbaev <Sergey.Kostanbaev at gmail.com>

Do not decode strings inside ss_request, leave it for upper level to 
support other languages. Parse Return Result accordingly.
Add default language decoding in gsm0480_decode_ussd_request() to not break 
current logic in OpenBSC.
Increase message storage to 160 bytes (or 182 symbols in gsm 7-bit encoding) 
instead of 31 bytes.
Store component type, invoke id and message type for USSD menu support
on upper level.

---
 include/osmocom/gsm/gsm0480.h |  26 ++++++---
 src/gsm/gsm0480.c             | 127 ++++++++++++++++++++++++++++++++++++------
 2 files changed, 130 insertions(+), 23 deletions(-)

diff --git a/include/osmocom/gsm/gsm0480.h b/include/osmocom/gsm/gsm0480.h
index deac322..094805f 100644
--- a/include/osmocom/gsm/gsm0480.h
+++ b/include/osmocom/gsm/gsm0480.h
@@ -5,7 +5,8 @@
 #include <osmocom/gsm/protocol/gsm_04_08.h>
 #include <osmocom/gsm/protocol/gsm_04_80.h>
 
-#define MAX_LEN_USSD_STRING	31
+#define MAX_LEN_USSD_STRING		182
+#define MAX_ASN1_LEN_USSD_STRING	160
 
 /* deprecated */
 struct ussd_request {
@@ -19,13 +20,24 @@ int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len,
 				struct ussd_request *request) OSMO_DEPRECATED("Use gsm0480_decode_ss_request() instead");
 
 struct ss_request {
-	uint8_t opcode;
-	uint8_t ss_code;
-	uint8_t ussd_text[MAX_LEN_USSD_STRING + 1];
-	uint8_t transaction_id;
-	uint8_t invoke_id;
-};
+	uint8_t transaction_id; /**< L3 transaction ID */
+	uint8_t message_type;   /**< Message type        2.2   */
+
+	uint8_t component_type; /**< Component type      3.6.2 */
+	uint8_t invoke_id;      /**< Invoke id           3.6.3 */
 
+	union {
+		uint8_t opcode;         /**< Operational code    3.6.4 */
+		uint8_t error_code;     /**< Error code          3.6.6 */
+		uint8_t problem_code;   /**< Problem code        3.6.7 */
+	};
+
+	uint8_t ussd_text_len;
+	uint8_t ussd_text_language;
+	uint8_t ussd_text[MAX_ASN1_LEN_USSD_STRING + 1];
+
+	uint8_t ss_code;       /**< parameters of a Interrogate/Activate/DeactivateSS Request */
+};
 int gsm0480_decode_ss_request(const struct gsm48_hdr *hdr, uint16_t len,
 				struct ss_request *request);
 
diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c
index 5d1377f..41eea5f 100644
--- a/src/gsm/gsm0480.c
+++ b/src/gsm/gsm0480.c
@@ -202,6 +202,8 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
 			     struct ss_request *req);
 static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
 					struct ss_request *req);
+static int parse_ss_return_result(const uint8_t *rr_data, uint16_t length,
+				  struct ss_request *req);
 static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length,
 					struct ss_request *req);
 static int parse_ss_for_bs_req(const uint8_t *ss_req_data,
@@ -231,10 +233,15 @@ int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len,
 		/* convert from ss_request to legacy ussd_request */
 		req->transaction_id = ss.transaction_id;
 		req->invoke_id = ss.invoke_id;
-		if (ss.ussd_text[0] == 0xFF)
+		if (ss.ussd_text_language != 0x0f ||
+			ss.opcode != GSM0480_OP_CODE_PROCESS_USS_REQ)
+
 			req->text[0] = '\0';
 		else {
-			memcpy(req->text, ss.ussd_text, sizeof(req->text));
+			gsm_7bit_decode_n_ussd(req->text,
+					       sizeof(req->text),
+					       ss.ussd_text, ss.ussd_text_len);
+
 			req->text[sizeof(req->text)-1] = '\0';
 		}
 	}
@@ -266,6 +273,7 @@ static int parse_ss(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request
 	int rc = 1;
 	uint8_t msg_type = hdr->msg_type & 0xBF;  /* message-type - section 3.4 */
 
+	req->message_type = msg_type;
 	switch (msg_type) {
 	case GSM0480_MTYPE_RELEASE_COMPLETE:
 		LOGP(0, LOGL_DEBUG, "SS Release Complete\n");
@@ -350,6 +358,8 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
 			return 0;
 		}
 
+		req->component_type = component_type;
+
 		switch (component_type) {
 		case GSM0480_CTYPE_INVOKE:
 			rc &= parse_ss_invoke(facility_ie+2,
@@ -357,10 +367,17 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
 					      req);
 			break;
 		case GSM0480_CTYPE_RETURN_RESULT:
+			rc &= parse_ss_return_result(facility_ie+2,
+						     component_length,
+						     req);
 			break;
 		case GSM0480_CTYPE_RETURN_ERROR:
+			/* TODO Error codes */
+			LOGP(0, LOGL_DEBUG, "Ignored GSM0480_CTYPE_RETURN_ERROR");
 			break;
 		case GSM0480_CTYPE_REJECT:
+			/* TODO rejects */
+			LOGP(0, LOGL_DEBUG, "Ignored GSM0480_CTYPE_REJECT");
 			break;
 		default:
 			LOGP(0, LOGL_DEBUG, "Unknown GSM 04.80 Facility "
@@ -374,6 +391,57 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
 	return rc;
 }
 
+/* Parse an Return Result component - see table 3.4 */
+static int parse_ss_return_result(const uint8_t *rr_data, uint16_t length,
+				  struct ss_request *req)
+{
+	int rc = 1;
+	uint8_t offset;
+
+	if (length < 3)
+		return 0;
+
+	/* mandatory part */
+	if (rr_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) {
+		LOGP(0, LOGL_DEBUG, "Unexpected GSM 04.80 Component-ID tag "
+		     "0x%02x (expecting Invoke ID tag)\n", rr_data[0]);
+	}
+
+	offset = rr_data[1] + 2;
+	req->invoke_id = rr_data[2];
+
+	if (offset < length) {
+		if (rr_data[offset] != GSM_0480_SEQUENCE_TAG)
+			return 0;
+		if (offset + 2 > length)
+			return 0;
+		offset += 2;
+
+		uint8_t operation_code = rr_data[offset+2];
+		req->opcode = operation_code;
+		switch (operation_code) {
+		case GSM0480_OP_CODE_USS_NOTIFY:
+		case GSM0480_OP_CODE_USS_REQUEST:
+		case GSM0480_OP_CODE_PROCESS_USS_REQ:
+			rc = parse_process_uss_req(rr_data + offset + 3,
+						   length - offset - 3,
+						   req);
+			break;
+		case GSM0480_OP_CODE_PROCESS_USS_DATA:
+			rc = parse_process_uss_data(rr_data + offset + 3,
+						    length - offset - 3,
+						    req);
+			break;
+		default:
+			LOGP(0, LOGL_DEBUG, "GSM 04.80 operation code 0x%02x "
+				"is not yet handled\n", operation_code);
+			rc = 0;
+			break;
+		}
+	}
+	return rc;
+}
+
 /* Parse an Invoke component - see table 3.3 */
 static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
 			   struct ss_request *req)
@@ -408,6 +476,8 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
 		uint8_t operation_code = invoke_data[offset+2];
 		req->opcode = operation_code;
 		switch (operation_code) {
+		case GSM0480_OP_CODE_USS_NOTIFY:
+		case GSM0480_OP_CODE_USS_REQUEST:
 		case GSM0480_OP_CODE_PROCESS_USS_REQ:
 			rc = parse_process_uss_req(invoke_data + offset + 3,
 						   length - offset - 3,
@@ -436,32 +506,57 @@ static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length,
 	return rc;
 }
 
+static const uint8_t *parse_asn1_small_len(const uint8_t *codedlen, uint16_t available,
+					   uint8_t *out_len)
+{
+	uint8_t lenb = codedlen[0];
+	if (lenb < 0x80 && available > 0) {
+		*out_len = lenb;
+		return &codedlen[1];
+	} else if (lenb == 0x81 && available > 1) {
+		*out_len = codedlen[1];
+		return &codedlen[2];
+	}
+
+	return NULL;
+}
+
 /* Parse the parameters of a Process UnstructuredSS Request */
 static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length,
 				 struct ss_request *req)
 {
 	int rc = 0;
-	int num_chars;
-	uint8_t dcs;
-
-
+	uint8_t dcs, seq_block_len, num_chars;
+	const uint8_t *next_ptr;
 	/* we need at least that much */
 	if (length < 8)
 		return 0;
 
 
 	if (uss_req_data[0] == GSM_0480_SEQUENCE_TAG) {
-		if (uss_req_data[2] == ASN1_OCTET_STRING_TAG) {
-			dcs = uss_req_data[4];
-			if ((dcs == 0x0F) &&
-			    (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) {
-				num_chars = (uss_req_data[6] * 8) / 7;
+		next_ptr = parse_asn1_small_len(&uss_req_data[1], length - 1, &seq_block_len);
+		if (next_ptr == NULL || seq_block_len < 6)
+			return 0;
+
+		if (next_ptr[0] == ASN1_OCTET_STRING_TAG) {
+			if (next_ptr[1] != 1)
+				return 0;
+
+			dcs = next_ptr[2];
+
+			if (next_ptr[3] == ASN1_OCTET_STRING_TAG) {
+				next_ptr = parse_asn1_small_len(&next_ptr[4],
+								seq_block_len - 4, &num_chars);
+				if (next_ptr == NULL)
+					return 0;
+
 				/* Prevent a mobile-originated buffer-overrun! */
-				if (num_chars > MAX_LEN_USSD_STRING)
-					num_chars = MAX_LEN_USSD_STRING;
-				gsm_7bit_decode_n_ussd((char *)req->ussd_text,
-							sizeof(req->ussd_text),
-							&(uss_req_data[7]), num_chars);
+				if (num_chars > MAX_ASN1_LEN_USSD_STRING)
+					num_chars = MAX_ASN1_LEN_USSD_STRING;
+
+				req->ussd_text_language = dcs;
+				req->ussd_text_len = num_chars;
+				memcpy(req->ussd_text, next_ptr, num_chars);
 				rc = 1;
 			}
 		}
-- 
1.9.1




More information about the OpenBSC mailing list