[PATCH 3/8] libmsc: Update USSD to use new ss_request structure

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 11:03:54 UTC 2015


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

Use new ss_request structure to support long messages and handle FACILITY
message type to support USSD menus.

---
 openbsc/include/openbsc/gsm_04_80.h |  11 ++--
 openbsc/src/libmsc/gsm_04_80.c      | 119 +++++++++++++++++++++++++++---------
 openbsc/src/libmsc/ussd.c           |  44 ++++++++-----
 3 files changed, 128 insertions(+), 46 deletions(-)

diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h
index 0a60652..08f974f 100644
--- a/openbsc/include/openbsc/gsm_04_80.h
+++ b/openbsc/include/openbsc/gsm_04_80.h
@@ -7,12 +7,15 @@
 
 struct gsm_subscriber_connection;
 
+int gsm0480_send_ussd(struct gsm_subscriber_connection *conn,
+		      struct ss_request *req);
+
 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 *resp_string,
+			       const struct ss_request *req);
+
 int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
-			     const struct msgb *msg, 
-			     const struct ussd_request *request);
+			     const struct ss_request *request);
 
 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/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c
index b30f9ee..4585202 100644
--- a/openbsc/src/libmsc/gsm_04_80.c
+++ b/openbsc/src/libmsc/gsm_04_80.c
@@ -39,6 +39,22 @@
 #include <osmocom/core/msgb.h>
 #include <osmocom/gsm/tlv.h>
 
+/* This function can handle ASN1 length up to 255 which is enough for USSD */
+static inline unsigned char *msgb_wrap_with_ASN1_TL(struct msgb *msgb, uint8_t tag)
+{
+	uint16_t origlen = msgb->len;
+	uint8_t *data = msgb_push(msgb, (origlen > 0x7f) ? 3 : 2);
+	data[0] = tag;
+	if (origlen > 0x7f) {
+		data[1] = 0x81;
+		data[2] = origlen;
+	} else {
+		data[1] = origlen;
+	}
+	return data;
+}
+
+
 static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag)
 {
 	uint8_t *data = msgb_push(msgb, 2);
@@ -59,59 +75,106 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
 	return data;
 }
 
+static inline unsigned char *msgb_wrap_with_L(struct msgb *msgb)
+{
+	uint8_t *data = msgb_push(msgb, 1);
+
+	data[0] = msgb->len - 1;
+	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 *resp_string,
+			       const struct ss_request* req)
+{
+	struct ss_request rss;
+	int response_len;
+
+	memset(&rss, 0, sizeof(rss));
+
+	gsm_7bit_encode_n_ussd(rss.ussd_text, MAX_LEN_USSD_STRING, resp_string, &response_len);
+	rss.ussd_text_len = response_len;
+	rss.ussd_text_language = 0x0f;
+
+	rss.transaction_id = req->transaction_id;
+	rss.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
+	rss.component_type = GSM0480_CTYPE_RETURN_RESULT;
+	rss.invoke_id = req->invoke_id;
+	rss.opcode = GSM0480_OP_CODE_PROCESS_USS_REQ;
+
+	return gsm0480_send_ussd(conn, &rss);
+}
+
+/* Compose universial SS packet except Reject opcodes */
+int gsm0480_send_ussd(struct gsm_subscriber_connection *conn,
+		      struct ss_request* req)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 	uint8_t *ptr8;
-	int response_len;
 
 	/* First put the payload text into the message */
 	ptr8 = msgb_put(msg, 0);
-	gsm_7bit_encode_n_ussd(ptr8, msgb_tailroom(msg), response_text, &response_len);
-	msgb_put(msg, response_len);
+
+	memcpy(ptr8, req->ussd_text, req->ussd_text_len);
+	msgb_put(msg, req->ussd_text_len);
 
 	/* Then wrap it as an Octet String */
-	msgb_wrap_with_TL(msg, ASN1_OCTET_STRING_TAG);
+	msgb_wrap_with_ASN1_TL(msg, ASN1_OCTET_STRING_TAG);
 
 	/* Pre-pend the DCS octet string */
-	msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, 0x0F);
+	msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_language);
 
 	/* Then wrap these as a Sequence */
-	msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG);
-
-	/* Pre-pend the operation code */
-	msgb_push_TLV1(msg, GSM0480_OPERATION_CODE,
-			GSM0480_OP_CODE_PROCESS_USS_REQ);
-
-	/* Wrap the operation code and IA5 string 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);
+	msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
+
+	if (req->component_type == GSM0480_CTYPE_RETURN_RESULT) {
+		/* Pre-pend the operation code */
+		msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
+
+		/* Wrap the operation code and IA5 string as a sequence */
+		msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
+
+		/* Pre-pend the invoke ID */
+		msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
+	} else if (req->component_type == GSM0480_CTYPE_INVOKE) {
+		/* Pre-pend the operation code */
+		msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
+
+		/* Pre-pend the invoke ID */
+		msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
+	} else {
+		abort();
+	}
+
+	/* Wrap this up as an Invoke or a Return Result component */
+	msgb_wrap_with_ASN1_TL(msg, req->component_type);
+
+	if (req->message_type == GSM0480_MTYPE_REGISTER ||
+		req->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
+		/* Wrap the component in a Facility message, it's not ASN1 */
+		msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
+	} else if (req->message_type == GSM0480_MTYPE_FACILITY) {
+		/* For GSM0480_MTYPE_FACILITY it's LV not TLV */
+		msgb_wrap_with_L(msg);
+	} else {
+		abort();
+	}
 
 	/* 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;
+	gh->msg_type = req->message_type;
+
+	DEBUGP(DSS, "Sending USSD to mobile: %s\n", msgb_hexdump(msg));
 
 	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)
+			     const struct ss_request *req)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
@@ -124,7 +187,7 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
 	msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
 
 	/* Wrap this up as a Reject component */
-	msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT);
+	msgb_wrap_with_ASN1_TL(msg, GSM0480_CTYPE_REJECT);
 
 	/* Wrap the component in a Facility message */
 	msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c
index 7f01eae..f0426c4 100644
--- a/openbsc/src/libmsc/ussd.c
+++ b/openbsc/src/libmsc/ussd.c
@@ -33,41 +33,57 @@
 #include <openbsc/gsm_subscriber.h>
 #include <openbsc/debug.h>
 #include <openbsc/osmo_msc.h>
+#include <openbsc/ussd.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsm0480.h>
 
 /* 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);
+static int send_own_number(struct gsm_subscriber_connection *conn, const struct ss_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 ss_request req;
+	char request_string[MAX_LEN_USSD_STRING + 1];
 	struct gsm48_hdr *gh;
 
 	memset(&req, 0, sizeof(req));
 	gh = msgb_l3(msg);
-	rc = gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req);
+	rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
 	if (!rc) {
-		DEBUGP(DMM, "Unhandled SS\n");
-		rc = gsm0480_send_ussd_reject(conn, msg, &req);
+		DEBUGP(DSS, "Unhandled SS\n");
+		rc = gsm0480_send_ussd_reject(conn, &req);
 		msc_release_connection(conn);
 		return rc;
 	}
 
-	/* Release-Complete */
-	if (req.text[0] == '\0')
+	if (req.message_type == GSM0480_MTYPE_RELEASE_COMPLETE)
 		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);
+	if (req.message_type != GSM0480_MTYPE_REGISTER ||
+			req.component_type != GSM0480_CTYPE_INVOKE ||
+			req.opcode != GSM0480_OP_CODE_PROCESS_USS_REQ ||
+			req.ussd_text_language != 0x0f)
+	{
+		DEBUGP(DSS, "Unexpected SS\n");
+		rc = gsm0480_send_ussd_reject(conn, &req);
+		msc_release_connection(conn);
+		return rc;
+	}
+
+	gsm_7bit_decode_n_ussd(request_string, MAX_LEN_USSD_STRING, req.ussd_text, req.ussd_text_len);
+
+	if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)request_string)) {
+		DEBUGP(DSS, "USSD: Own number requested\n");
+		rc = send_own_number(conn, &req);
 	} else {
-		DEBUGP(DMM, "Unhandled USSD %s\n", req.text);
-		rc = gsm0480_send_ussd_reject(conn, msg, &req);
+		DEBUGP(DSS, "Unhandled USSD %s\n", request_string);
+		rc = gsm0480_send_ussd_reject(conn, &req);
 	}
 
 	/* check if we can release it */
@@ -76,12 +92,12 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
 }
 
 /* A network-specific handler function */
-static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req)
+static int send_own_number(struct gsm_subscriber_connection *conn, 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, msg, response_string, req);
+	return gsm0480_send_ussd_response(conn, response_string, req);
 }
-- 
1.9.1




More information about the OpenBSC mailing list