From 76ef72dda892b8ec4b64bba2fb700763196540c9 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Wed, 7 Nov 2018 05:08:18 +0700 Subject: [PATCH] libmsc/gsm_04_11.c: forward MO SMS messages over GSUP Change-Id: I7d651fde3d608d02f275a74043dc42262aabb1b8 Depends-on: (core) Ic37f3b2114b8095cfce22977e67133b9103942e3 Depends-on: (core) Ibe325c64ae2d6c626b232533bb4cbc65fc2b5d71 Depends-on: (OsmoHLR) I0589ff27933e9bca2bcf93b8259004935778db8f Related Change-Id: (TTCN) I7abc95b8e416f7308d54e11be11c08586d18e6c5 Related Change-Id: (TTCN) Id14bbd8bd51558cdacefea0fe042769cd69ed5c8 Related: OS#3587 --- include/osmocom/msc/Makefile.am | 1 + include/osmocom/msc/gsm_04_11.h | 1 + include/osmocom/msc/gsm_04_11_gsup.h | 14 ++ src/libmsc/Makefile.am | 1 + src/libmsc/gsm_04_08.c | 8 ++ src/libmsc/gsm_04_11.c | 23 ++- src/libmsc/gsm_04_11_gsup.c | 203 +++++++++++++++++++++++++++ 7 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 include/osmocom/msc/gsm_04_11_gsup.h create mode 100644 src/libmsc/gsm_04_11_gsup.c diff --git a/include/osmocom/msc/Makefile.am b/include/osmocom/msc/Makefile.am index d98bc9cb5..13ac166d4 100644 --- a/include/osmocom/msc/Makefile.am +++ b/include/osmocom/msc/Makefile.am @@ -5,6 +5,7 @@ noinst_HEADERS = \ debug.h \ gsm_04_08.h \ gsm_04_11.h \ + gsm_04_11_gsup.h \ gsm_04_14.h \ gsm_04_80.h \ gsm_09_11.h \ diff --git a/include/osmocom/msc/gsm_04_11.h b/include/osmocom/msc/gsm_04_11.h index 95098c9b3..b739918b1 100644 --- a/include/osmocom/msc/gsm_04_11.h +++ b/include/osmocom/msc/gsm_04_11.h @@ -2,6 +2,7 @@ #define _GSM_04_11_H #include +#include struct vlr_subscr; struct ran_conn; diff --git a/include/osmocom/msc/gsm_04_11_gsup.h b/include/osmocom/msc/gsm_04_11_gsup.h new file mode 100644 index 000000000..94ff8f670 --- /dev/null +++ b/include/osmocom/msc/gsm_04_11_gsup.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +struct osmo_gsup_message; +struct vlr_subscr; +struct gsm_trans; +struct msgb; + +int gsm411_gsup_mo_ready_for_sm_req(struct gsm_trans *trans, uint8_t sm_rp_mr); +int gsm411_gsup_mo_fwd_sm_req(struct gsm_trans *trans, struct msgb *msg, + uint8_t sm_rp_mr, uint8_t *sm_rp_da, uint8_t sm_rp_da_len); +int gsm411_gsup_mo_handler(struct vlr_subscr *vsub, + struct osmo_gsup_message *gsup_msg); diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am index 9183ff9a0..72da747c2 100644 --- a/src/libmsc/Makefile.am +++ b/src/libmsc/Makefile.am @@ -35,6 +35,7 @@ libmsc_a_SOURCES = \ gsm_04_08.c \ gsm_04_08_cc.c \ gsm_04_11.c \ + gsm_04_11_gsup.c \ gsm_04_14.c \ gsm_04_80.c \ gsm_09_11.c \ diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c index dc0476b55..b042baf71 100644 --- a/src/libmsc/gsm_04_08.c +++ b/src/libmsc/gsm_04_08.c @@ -1791,6 +1791,14 @@ static int msc_vlr_route_gsup_msg(struct vlr_subscr *vsub, DEBUGP(DMSC, "Routed to GSM 09.11 SS/USSD handler\n"); return gsm0911_gsup_handler(vsub, gsup_msg); + /* GSM 04.11 code implementing MO SMS */ + case OSMO_GSUP_MSGT_MO_FORWARD_SM_ERROR: + case OSMO_GSUP_MSGT_MO_FORWARD_SM_RESULT: + case OSMO_GSUP_MSGT_READY_FOR_SM_ERROR: + case OSMO_GSUP_MSGT_READY_FOR_SM_RESULT: + DEBUGP(DMSC, "Routed to GSM 04.11 MO handler\n"); + return gsm411_gsup_mo_handler(vsub, gsup_msg); + default: LOGP(DMM, LOGL_ERROR, "No handler found for %s, dropping message...\n", osmo_gsup_message_type_name(gsup_msg->message_type)); diff --git a/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c index 62f3bbafd..788a0a946 100644 --- a/src/libmsc/gsm_04_11.c +++ b/src/libmsc/gsm_04_11.c @@ -664,10 +664,20 @@ int gsm411_send_rp_error(struct gsm_trans *trans, uint8_t msg_ref, /* Receive a 04.11 TPDU inside RP-DATA / user data */ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans, - struct gsm411_rp_hdr *rph) + struct gsm411_rp_hdr *rph, + uint8_t *dst, uint8_t dst_len) { int rc = 0; + if (trans->net->sms_over_gsup) { + /* RP-ACK or RP-ERROR is triggered as soon as we get the response */ + rc = gsm411_gsup_mo_fwd_sm_req(trans, msg, rph->msg_ref, dst, dst_len); + if (rc) /* GSUP message sending error */ + return gsm411_send_rp_error(trans, rph->msg_ref, rc); + + return 0; + } + rc = gsm340_rx_tpdu(trans, msg, rph->msg_ref); if (rc == 0) return gsm411_send_rp_ack(trans, rph->msg_ref); @@ -715,7 +725,7 @@ static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans, DEBUGP(DLSMS, "DST(%u,%s)\n", dst_len, osmo_hexdump(dst, dst_len)); - return gsm411_rx_rp_ud(msg, trans, rph); + return gsm411_rx_rp_ud(msg, trans, rph, dst, dst_len); } static struct gsm_sms *sms_report_alloc(struct gsm_sms *sms) @@ -852,6 +862,15 @@ static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans, { int rc; + if (trans->net->sms_over_gsup) { + /* RP-ACK or RP-ERROR is triggered as soon as we get the response */ + rc = gsm411_gsup_mo_ready_for_sm_req(trans, rph->msg_ref); + if (rc) /* GSUP message sending error */ + return gsm411_send_rp_error(trans, rph->msg_ref, rc); + + return 0; + } + rc = gsm411_send_rp_ack(trans, rph->msg_ref); /* MS tells us that it has memory for more SMS, we need diff --git a/src/libmsc/gsm_04_11_gsup.c b/src/libmsc/gsm_04_11_gsup.c new file mode 100644 index 000000000..5c0107245 --- /dev/null +++ b/src/libmsc/gsm_04_11_gsup.c @@ -0,0 +1,203 @@ +/* + * (C) 2018 by Vadim Yanitskiy + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Common helper for preparing to be encoded GSUP message */ +static void gsup_sm_msg_init(struct osmo_gsup_message *gsup_msg, + enum osmo_gsup_message_type msg_type, const char *imsi, + uint8_t *sm_rp_mr) +{ + /* Init a mew GSUP message */ + memset(gsup_msg, 0x00, sizeof(*gsup_msg)); + gsup_msg->message_type = msg_type; + + /* SM-RP-MR (Message Reference) */ + gsup_msg->sm_rp_mr = sm_rp_mr; + + /* Fill in subscriber's IMSI */ + OSMO_STRLCPY_ARRAY(gsup_msg->imsi, imsi); +} + +int gsm411_gsup_mo_fwd_sm_req(struct gsm_trans *trans, struct msgb *msg, + uint8_t sm_rp_mr, uint8_t *sm_rp_da, uint8_t sm_rp_da_len) +{ + uint8_t bcd_buf[GSM48_MI_SIZE] = { 0 }; + struct osmo_gsup_message gsup_msg; + size_t bcd_len; + + /* Associate logging messages with this subscriber */ + log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub); + + LOGP(DLSMS, LOGL_DEBUG, "TX GSUP MO-forwardSM-Req\n"); + + /* Assign SM-RP-MR to transaction state */ + trans->sms.sm_rp_mr = sm_rp_mr; + + /* Encode subscriber's MSISDN */ + bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), + 0, trans->vsub->msisdn); + if (bcd_len <= 0 || bcd_len > sizeof(bcd_buf)) { + LOGP(DLSMS, LOGL_ERROR, "Failed to encode subscriber's MSISDN\n"); + return -EINVAL; + } + + /* Initialize a new GSUP message */ + gsup_sm_msg_init(&gsup_msg, OSMO_GSUP_MSGT_MO_FORWARD_SM_REQUEST, + trans->vsub->imsi, &sm_rp_mr); + + /* According to 12.2.3, the MSISDN from VLR is inserted here */ + gsup_msg.sm_rp_oa_type = OSMO_GSUP_SMS_SM_RP_ODA_MSISDN; + gsup_msg.sm_rp_oa_len = bcd_len; + gsup_msg.sm_rp_oa = bcd_buf; + + /* SM-RP-DA should (already) contain SMSC address */ + gsup_msg.sm_rp_da_type = OSMO_GSUP_SMS_SM_RP_ODA_SMSC_ADDR; + gsup_msg.sm_rp_da_len = sm_rp_da_len; + gsup_msg.sm_rp_da = sm_rp_da; + + /* SM-RP-UI (TPDU) is pointed by msgb->l4h */ + gsup_msg.sm_rp_ui_len = msgb_l4len(msg); + gsup_msg.sm_rp_ui = (uint8_t *) msgb_sms(msg); + + return osmo_gsup_client_enc_send(trans->net->vlr->gsup_client, &gsup_msg); +} + +int gsm411_gsup_mo_ready_for_sm_req(struct gsm_trans *trans, uint8_t sm_rp_mr) +{ + struct osmo_gsup_message gsup_msg; + + /* Associate logging messages with this subscriber */ + log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub); + + LOGP(DLSMS, LOGL_DEBUG, "TX GSUP READY-FOR-SM Req\n"); + + /* Assign SM-RP-MR to transaction state */ + trans->sms.sm_rp_mr = sm_rp_mr; + + /* Initialize a new GSUP message */ + gsup_sm_msg_init(&gsup_msg, OSMO_GSUP_MSGT_READY_FOR_SM_REQUEST, + trans->vsub->imsi, &sm_rp_mr); + + /* Indicate SMMA as the Alert Reason */ + gsup_msg.sm_alert_rsn = OSMO_GSUP_SMS_SM_ALERT_RSN_MEM_AVAIL; + + return osmo_gsup_client_enc_send(trans->net->vlr->gsup_client, &gsup_msg); +} + +/* Triggers either RP-ACK or RP-ERROR on response from SMSC */ +int gsm411_gsup_mo_handler(struct vlr_subscr *vsub, + struct osmo_gsup_message *gsup_msg) +{ + struct vlr_instance *vlr; + struct gsm_network *net; + struct gsm_trans *trans; + struct ran_conn *conn; + const char *msg_name; + bool msg_is_err; + + /* Obtain required pointers */ + vlr = vsub->vlr; + net = (struct gsm_network *) vlr->user_ctx; + + /* Associate logging messages with this subscriber */ + log_set_context(LOG_CTX_VLR_SUBSCR, vsub); + + /* Determine the message type and name */ + msg_is_err = OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type); + switch (gsup_msg->message_type) { + case OSMO_GSUP_MSGT_MO_FORWARD_SM_ERROR: + case OSMO_GSUP_MSGT_MO_FORWARD_SM_RESULT: + msg_name = "MO-forwardSM"; + break; + case OSMO_GSUP_MSGT_READY_FOR_SM_ERROR: + case OSMO_GSUP_MSGT_READY_FOR_SM_RESULT: + msg_name = "MO-ReadyForSM"; + break; + default: + /* Shall not happen */ + OSMO_ASSERT(0); + } + + LOGP(DLSMS, LOGL_DEBUG, "RX %s-%s\n", msg_name, + msg_is_err ? "Err" : "Res"); + + /* Make sure that 'SMS over GSUP' is expected */ + if (!net->sms_over_gsup) { + /* TODO: notify sender about that? */ + LOGP(DLSMS, LOGL_NOTICE, "Unexpected MO SMS over GSUP, " + "ignoring message...\n"); + return -EIO; + } + + /* Verify GSUP message */ + if (!gsup_msg->sm_rp_mr) + goto msg_error; + if (msg_is_err && !gsup_msg->sm_rp_cause) + goto msg_error; + + /* Attempt to find a DTAP-connection */ + conn = connection_for_subscr(vsub); + if (!conn) { + /* FIXME: should we establish it then? */ + LOGP(DLSMS, LOGL_NOTICE, "No connection found for %s, " + "ignoring %s-%s message...\n", vlr_subscr_name(vsub), + msg_name, msg_is_err ? "Err" : "Res"); + return -EIO; /* TODO: notify sender about that? */ + } + + /* Attempt to find DTAP-transaction */ + trans = trans_find_by_sm_rp_mr(conn, *(gsup_msg->sm_rp_mr)); + if (!trans) { + LOGP(DLSMS, LOGL_NOTICE, "No transaction found for %s, " + "ignoring %s-%s message...\n", vlr_subscr_name(vsub), + msg_name, msg_is_err ? "Err" : "Res"); + return -EIO; /* TODO: notify sender about that? */ + } + + /* Send either RP-ERROR, or RP-ACK */ + if (msg_is_err) { + /* TODO: handle optional SM-RP-UI payload (requires API change) */ + gsm411_send_rp_error(trans, *(gsup_msg->sm_rp_mr), + *(gsup_msg->sm_rp_cause)); + } else { + gsm411_send_rp_ack(trans, *(gsup_msg->sm_rp_mr)); + } + + return 0; + +msg_error: + /* TODO: notify sender about that? */ + LOGP(DLSMS, LOGL_NOTICE, "RX malformed %s-%s\n", + msg_name, msg_is_err ? "Err" : "Res"); + return -EINVAL; +}