From patchwork Fri Apr 22 12:41:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergey Kostanbaev X-Patchwork-Id: 613586 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.osmocom.org (lists.osmocom.org [IPv6:2a01:4f8:191:444b::2:7]) by ozlabs.org (Postfix) with ESMTP id 3qrwH81XFbz9t3q for ; Fri, 22 Apr 2016 22:41:56 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=X/lcbFD0; dkim-atps=neutral Received: from lists.osmocom.org (lists.osmocom.org [144.76.43.76]) by lists.osmocom.org (Postfix) with ESMTP id 5A216131A3; Fri, 22 Apr 2016 12:41:54 +0000 (UTC) X-Original-To: openbsc@lists.osmocom.org Delivered-To: openbsc@lists.osmocom.org Received: from mail-wm0-x231.google.com (mail-wm0-x231.google.com [IPv6:2a00:1450:400c:c09::231]) by lists.osmocom.org (Postfix) with ESMTP id 83B2C13173 for ; Fri, 22 Apr 2016 12:41:49 +0000 (UTC) Received: by mail-wm0-x231.google.com with SMTP id n3so25115887wmn.0 for ; Fri, 22 Apr 2016 05:41:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=YW75W/FJzK5yn/FxrbsQQIMcJmVIT+munupr5F6/Sr8=; b=X/lcbFD0R4Xqv/yiU+tJUpwaoIAX95llKZ+eC0j4DNmfIy6UEzvgGnilq/4JCJkZ5P wSoEmD3xohFRN28hFtca5atw5cre1Uy3hDk4eBXl44vTqyqnXtDgzO3dIhIQGky0qNrB KjvJU09+4o6z5c8NKclrFSO3CgUcGFCN41BMVq4+WtRNxgSqH65l7inJ5BhGuoU5T0WF 8ljR7yEh3gO9OoQaNW5YGJgf4iTE0QZH5kayzQ32BEiK/wRk9kKVMiboo17QodAHXh4f dxawHf4+NfEsvw3fxM12Wg6dWuuvAf9tWklHuavoKuet4MWExVlRSOETP+V1KXOlYyrq H/XA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=YW75W/FJzK5yn/FxrbsQQIMcJmVIT+munupr5F6/Sr8=; b=P+EOkNrAAjqSjnexolzpcs2Pp+pbLRZm3c0nyNAeD51c0TB0u4lv6/MSPjeZCN8ybQ LL8EYfzfRxO6VaoqRNd38LhpawTOpG42ir+/zjq4eGr/iQeEkR7BxgH+M77Zh/pWL1sD SPe4H9SM1JW8XO8UQzecvketIk7fBolt8QAM2weLsjsqeNu1ZIfkptTQ5EjdUahCVdMw i0cR6y52WbFe+6TyAozX4At13yAUxc0HVsa/COcVtSgX9YZGXEECEPcDlYHu5FE1wODl UlyJpPgkeWBKHstDdJloUTwZofY9DZKNtsk0I18+NfBZW2BpFSUmejWaVYXkkQSPSuWy TiyA== X-Gm-Message-State: AOPr4FUYXPR7tL8K65nakD95P4p6bJOn6p4hcEU9iHvvs2ghifFUJuBb+1EcTimcCxT+wA== X-Received: by 10.194.246.137 with SMTP id xw9mr21552680wjc.172.1461328909285; Fri, 22 Apr 2016 05:41:49 -0700 (PDT) Received: from serg-X55SR.in-berlin.de ([185.11.247.108]) by smtp.gmail.com with ESMTPSA id b15sm3224216wmd.1.2016.04.22.05.41.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 22 Apr 2016 05:41:48 -0700 (PDT) From: Sergey Kostanbaev To: openbsc@lists.osmocom.org Subject: [PATCH 3/9] libmsc: Update USSD to use new ss_request structure Date: Fri, 22 Apr 2016 14:41:32 +0200 Message-Id: <1461328898-8298-3-git-send-email-sergey.kostanbaev@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1461328898-8298-1-git-send-email-sergey.kostanbaev@gmail.com> References: <1461328898-8298-1-git-send-email-sergey.kostanbaev@gmail.com> X-BeenThere: openbsc@lists.osmocom.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Development of OpenBSC, OsmoBSC, OsmoNITB, OsmoCSCN" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openbsc-bounces@lists.osmocom.org Sender: "OpenBSC" --- openbsc/include/openbsc/gsm_04_80.h | 15 +++-- openbsc/src/libmsc/gsm_04_80.c | 128 ++++++++++++++++++++++++------------ openbsc/src/libmsc/ussd.c | 79 ++++++++++++++++++---- 3 files changed, 162 insertions(+), 60 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index 0a60652..371bc17 100644 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -7,12 +7,17 @@ struct gsm_subscriber_connection; -int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, - const struct msgb *in_msg, const char* response_text, - const struct ussd_request *req); +int gsm0480_send_component(struct gsm_subscriber_connection *conn, + struct msgb *msg, + struct ss_header* reqhdr); + int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, - const struct msgb *msg, - const struct ussd_request *request); + uint8_t invoke_id, + uint8_t transaction_id); + +struct msgb *gsm0480_compose_ussd_component(struct ss_request* req); + + 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 f1d75f2..e6e4a92 100644 --- a/openbsc/src/libmsc/gsm_04_80.c +++ b/openbsc/src/libmsc/gsm_04_80.c @@ -39,6 +39,22 @@ #include #include +/* 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,83 +75,111 @@ 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); -/* 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) + data[0] = msgb->len - 1; + return data; +} + +/* Compose universial USSD packet invoke/return_result payload */ +struct msgb *gsm0480_compose_ussd_component(struct ss_request* req) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD RSP"); - 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); + 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); + return msg; +} - /* Pre-pend the invoke ID */ - msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); +#ifndef NO_GSM0480_SEND_FUNC - /* Wrap this up as a Return Result component */ - msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT); +int gsm0480_send_component(struct gsm_subscriber_connection *conn, + struct msgb *msg, + struct ss_header* reqhdr) +{ + struct gsm48_hdr *gh; - /* Wrap the component in a Facility message */ - msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); + if (reqhdr->message_type == GSM0480_MTYPE_REGISTER || + reqhdr->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 (reqhdr->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 + gh->proto_discr = GSM48_PDISC_NC_SS | reqhdr->transaction_id | (1<<7); /* TI direction = 1 */ - gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; + gh->msg_type = reqhdr->message_type; + + DEBUGP(DSS, "Sending SS 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) + uint8_t invoke_id, + uint8_t transaction_id) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REJ"); - struct gsm48_hdr *gh; + struct ss_header ssh; /* First insert the problem code */ msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL, GSM_0480_GEN_PROB_CODE_UNRECOGNISED); /* Before it insert the invoke ID */ - msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id); /* Wrap this up as a Reject component */ - msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT); - - /* Wrap the component in a Facility message */ - msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); + msgb_wrap_with_ASN1_TL(msg, GSM0480_CTYPE_REJECT); - /* And finally pre-pend the L3 header */ - gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_NC_SS; - gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */ - gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; - - return gsm0808_submit_dtap(conn, msg, 0, 0); + /* Prepare data for L3 header */ + ssh.transaction_id = transaction_id; + ssh.message_type = GSM0480_MTYPE_RELEASE_COMPLETE; + return gsm0480_send_component(conn, msg, &ssh); } int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text) @@ -173,3 +217,5 @@ int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn) return gsm0808_submit_dtap(conn, msg, 0, 0); } + +#endif diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c index 7f01eae..3cafe02 100644 --- a/openbsc/src/libmsc/ussd.c +++ b/openbsc/src/libmsc/ussd.c @@ -33,41 +33,71 @@ #include #include #include +#include +#include +#include /* 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_header *reqhdr, + 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_header reqhdr; + struct ss_request req; + char request_string[MAX_LEN_USSD_STRING + 1]; struct gsm48_hdr *gh; memset(&req, 0, sizeof(req)); + memset(&reqhdr, 0, sizeof(reqhdr)); gh = msgb_l3(msg); - rc = gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req); + rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &reqhdr); if (!rc) { - DEBUGP(DMM, "Unhandled SS\n"); - rc = gsm0480_send_ussd_reject(conn, msg, &req); + DEBUGP(DSS, "Incorrect SS header\n"); msc_release_connection(conn); return rc; } - /* Release-Complete */ - if (req.text[0] == '\0') + rc = gsm0480_parse_ss_facility(gh->data + reqhdr.component_offset, + reqhdr.component_length, + &req); + if (!rc) { + DEBUGP(DSS, "Unhandled SS\n"); + /* TODO req.invoke_id may not be set!!! */ + rc = gsm0480_send_ussd_reject(conn, req.invoke_id, reqhdr.transaction_id); + msc_release_connection(conn); + return rc; + } + + if (reqhdr.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 (reqhdr.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.invoke_id, reqhdr.transaction_id); + 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, &reqhdr, &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.invoke_id, reqhdr.transaction_id); } /* check if we can release it */ @@ -76,12 +106,33 @@ 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_header *reqhdr, + const struct ss_request *req) { + struct ss_request rss; + struct ss_header rssh; + char *own_number = conn->subscr->extension; char response_string[GSM_EXTENSION_LENGTH + 20]; + int response_len; /* 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); + + memset(&rss, 0, sizeof(rss)); + gsm_7bit_encode_n_ussd(rss.ussd_text, MAX_LEN_USSD_STRING, response_string, &response_len); + rss.ussd_text_len = response_len; + rss.ussd_text_language = 0x0f; + + rss.component_type = GSM0480_CTYPE_RETURN_RESULT; + rss.invoke_id = req->invoke_id; + rss.opcode = GSM0480_OP_CODE_PROCESS_USS_REQ; + + rssh.message_type = GSM0480_MTYPE_RELEASE_COMPLETE; + rssh.transaction_id = reqhdr->transaction_id; + + return gsm0480_send_component(conn, + gsm0480_compose_ussd_component(&rss), + &rssh); }