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
This commit is contained in:
parent
f40e46fdf4
commit
76ef72dda8
|
@ -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 \
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _GSM_04_11_H
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_04_11.h>
|
||||
#include <osmocom/msc/gsm_04_11_gsup.h>
|
||||
|
||||
struct vlr_subscr;
|
||||
struct ran_conn;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
|
@ -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 \
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
#include <osmocom/msc/gsm_subscriber.h>
|
||||
#include <osmocom/msc/transaction.h>
|
||||
#include <osmocom/msc/msc_common.h>
|
||||
#include <osmocom/msc/debug.h>
|
||||
#include <osmocom/msc/vlr.h>
|
||||
|
||||
/* 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;
|
||||
}
|
Loading…
Reference in New Issue