|
|
|
/* Point-to-Point (PP) Short Message Service (SMS)
|
|
|
|
* Support on Mobile Radio Interface
|
|
|
|
* 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */
|
|
|
|
|
|
|
|
/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
|
|
|
|
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
|
|
|
* (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
|
|
|
* (C) 2010 by On-Waves
|
|
|
|
* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
*
|
|
|
|
* 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 <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
#include "bscconfig.h"
|
|
|
|
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/talloc.h>
|
|
|
|
#include <osmocom/core/utils.h>
|
|
|
|
|
|
|
|
#include <osmocom/gsm/gsm_utils.h>
|
|
|
|
#include <osmocom/gsm/gsm0411_utils.h>
|
|
|
|
#include <osmocom/gsm/protocol/gsm_04_11.h>
|
|
|
|
|
|
|
|
#include <osmocom/msc/debug.h>
|
|
|
|
#include <osmocom/msc/gsm_data.h>
|
|
|
|
#include <osmocom/msc/db.h>
|
|
|
|
#include <osmocom/msc/gsm_subscriber.h>
|
|
|
|
#include <osmocom/msc/gsm_04_08.h>
|
|
|
|
#include <osmocom/msc/signal.h>
|
|
|
|
#include <osmocom/msc/db.h>
|
|
|
|
#include <osmocom/msc/transaction.h>
|
|
|
|
#include <osmocom/msc/msc_ifaces.h>
|
|
|
|
#include <osmocom/msc/vlr.h>
|
|
|
|
|
|
|
|
#ifdef BUILD_SMPP
|
|
|
|
#include "smpp_smsc.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void *tall_gsms_ctx;
|
|
|
|
static uint32_t new_callref = 0x40000001;
|
|
|
|
|
|
|
|
|
|
|
|
struct gsm_sms *sms_alloc(void)
|
|
|
|
{
|
|
|
|
return talloc_zero(tall_gsms_ctx, struct gsm_sms);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sms_free(struct gsm_sms *sms)
|
|
|
|
{
|
|
|
|
/* drop references to subscriber structure */
|
|
|
|
if (sms->receiver)
|
|
|
|
vlr_subscr_put(sms->receiver, VSUB_USE_SMS_RECEIVER);
|
|
|
|
#ifdef BUILD_SMPP
|
|
|
|
if (sms->smpp.esme)
|
|
|
|
smpp_esme_put(sms->smpp.esme);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
talloc_free(sms);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct gsm_sms *sms_from_text(struct vlr_subscr *receiver,
|
|
|
|
const char *sender_msisdn,
|
|
|
|
int dcs, const char *text)
|
|
|
|
{
|
|
|
|
struct gsm_sms *sms = sms_alloc();
|
|
|
|
|
|
|
|
if (!sms)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
vlr_subscr_get(receiver, VSUB_USE_SMS_RECEIVER);
|
|
|
|
sms->receiver = receiver;
|
|
|
|
OSMO_STRLCPY_ARRAY(sms->text, text);
|
|
|
|
|
|
|
|
OSMO_STRLCPY_ARRAY(sms->src.addr, sender_msisdn);
|
|
|
|
sms->reply_path_req = 0;
|
|
|
|
sms->status_rep_req = 0;
|
|
|
|
sms->ud_hdr_ind = 0;
|
|
|
|
sms->protocol_id = 0; /* implicit */
|
|
|
|
sms->data_coding_scheme = dcs;
|
|
|
|
OSMO_STRLCPY_ARRAY(sms->dst.addr, receiver->msisdn);
|
|
|
|
/* Generate user_data */
|
|
|
|
sms->user_data_len = gsm_7bit_encode_n(sms->user_data, sizeof(sms->user_data),
|
|
|
|
sms->text, NULL);
|
|
|
|
|
|
|
|
return sms;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void send_signal(int sig_no,
|
|
|
|
struct gsm_trans *trans,
|
|
|
|
struct gsm_sms *sms,
|
|
|
|
int paging_result)
|
|
|
|
{
|
|
|
|
struct sms_signal_data sig;
|
|
|
|
sig.trans = trans;
|
|
|
|
sig.sms = sms;
|
|
|
|
sig.paging_result = paging_result;
|
|
|
|
osmo_signal_dispatch(SS_SMS, sig_no, &sig);
|
|
|
|
}
|
|
|
|
|
rename gsm_subscriber_connection to ran_conn
In preparation for inter-BSC and inter-MSC handover, we need to separate the
subscriber management logic from the actual RAN connections. What better time
to finally rename gsm_subscriber_connection.
* Name choice:
In 2G, this is a connection to the BSS, but even though 3GPP TS commonly talk
of "BSS-A" and "BSS-B" when explaining handover, it's not good to call it
"bss_conn": in 3G a BSS is called RNS, IIUC.
The overall term for 2G (GERAN) and 3G (UTRAN) is RAN: Radio Access Network.
* Rationale:
A subscriber in the MSC so far has only one RAN connection, but e.g. for
inter-BSC handover, a second one needs to be created to handover to. Most of
the items in the former gsm_subscriber_connection are actually related to the
RAN, with only a few MM and RTP related items. So, as a first step, just rename
it to ran_conn, to cosmetically prepare for moving the not strictly RAN related
items away later.
Also:
- Rename some functions from msc_subscr_conn_* to ran_conn_*
- Rename "Subscr_Conn" FSM instance name to "RAN_conn"
- Rename SUBSCR_CONN_* to RAN_CONN_*
Change-Id: Ic595f7a558d3553c067f77dc67543ab59659707a
4 years ago
|
|
|
static int gsm411_sendmsg(struct ran_conn *conn, struct msgb *msg)
|
|
|
|
{
|
|
|
|
DEBUGP(DLSMS, "GSM4.11 TX %s\n", msgb_hexdump(msg));
|
|
|
|
msg->l3h = msg->data;
|
|
|
|
return msc_tx_dtap(conn, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Paging callback for MT SMS (Paging is triggered by SMC) */
|
|
|
|
static int paging_cb_mmsms_est_req(unsigned int hooknum, unsigned int event,
|
|
|
|
struct msgb *msg, void *_conn, void *_trans)
|
|
|
|
{
|
rename gsm_subscriber_connection to ran_conn
In preparation for inter-BSC and inter-MSC handover, we need to separate the
subscriber management logic from the actual RAN connections. What better time
to finally rename gsm_subscriber_connection.
* Name choice:
In 2G, this is a connection to the BSS, but even though 3GPP TS commonly talk
of "BSS-A" and "BSS-B" when explaining handover, it's not good to call it
"bss_conn": in 3G a BSS is called RNS, IIUC.
The overall term for 2G (GERAN) and 3G (UTRAN) is RAN: Radio Access Network.
* Rationale:
A subscriber in the MSC so far has only one RAN connection, but e.g. for
inter-BSC handover, a second one needs to be created to handover to. Most of
the items in the former gsm_subscriber_connection are actually related to the
RAN, with only a few MM and RTP related items. So, as a first step, just rename
it to ran_conn, to cosmetically prepare for moving the not strictly RAN related
items away later.
Also:
- Rename some functions from msc_subscr_conn_* to ran_conn_*
- Rename "Subscr_Conn" FSM instance name to "RAN_conn"
- Rename SUBSCR_CONN_* to RAN_CONN_*
Change-Id: Ic595f7a558d3553c067f77dc67543ab59659707a
4 years ago
|
|
|
struct ran_conn *conn = _conn;
|
|
|
|
struct gsm_trans *trans = _trans;
|
|
|
|
struct gsm_sms *sms = trans->sms.sms;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
DEBUGP(DLSMS, "paging_cb_mmsms_est_req(hooknum=%u, event=%u)\n", hooknum, event);
|
|
|
|
|
|
|
|
if (hooknum != GSM_HOOK_RR_PAGING)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Paging procedure has finished */
|
|
|
|
trans->paging_request = NULL;
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case GSM_PAGING_SUCCEEDED:
|
|
|
|
/* Associate transaction with established connection */
|
|
|
|
trans->conn = ran_conn_get(conn, RAN_CONN_USE_TRANS_SMS);
|
|
|
|
/* Confirm successful connection establishment */
|
|
|
|
gsm411_smc_recv(&trans->sms.smc_inst,
|
|
|
|
GSM411_MMSMS_EST_CNF, NULL, 0);
|
|
|
|
break;
|
|
|
|
case GSM_PAGING_EXPIRED:
|
|
|
|
case GSM_PAGING_BUSY:
|
|
|
|
/* Inform SMC about channel establishment failure */
|
|
|
|
gsm411_smc_recv(&trans->sms.smc_inst,
|
|
|
|
GSM411_MMSMS_REL_IND, NULL, 0);
|
|
|
|
|
|
|
|
/* gsm411_send_rp_data() doesn't set trans->sms.sms */
|
|
|
|
if (sms != NULL) {
|
|
|
|
/* Notify the SMSqueue and free stored SMS */
|
|
|
|
send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, event);
|
|
|
|
trans->sms.sms = NULL;
|
|
|
|
sms_free(sms);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Destroy this transaction */
|
|
|
|
trans_free(trans);
|
|
|
|
rc = -ETIMEDOUT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DLSMS, LOGL_ERROR, "Unhandled paging event: %d\n", event);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm411_mmsms_est_req(struct gsm_trans *trans)
|
|
|
|
{
|
|
|
|
/* Subscriber's data shall be associated */
|
|
|
|
OSMO_ASSERT(trans->vsub != NULL);
|
|
|
|
|
|
|
|
/* Check if connection is already established */
|
|
|
|
if (trans->conn != NULL) {
|
|
|
|
LOGP(DLSMS, LOGL_DEBUG, "Using an existing connection "
|
|
|
|
"for %s\n", vlr_subscr_name(trans->vsub));
|
|
|
|
return gsm411_smc_recv(&trans->sms.smc_inst,
|
|
|
|
GSM411_MMSMS_EST_CNF, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initiate Paging procedure */
|
|
|
|
LOGP(DLSMS, LOGL_DEBUG, "Initiating Paging procedure "
|
|
|
|
"for %s due to MMSMS_EST_REQ\n", vlr_subscr_name(trans->vsub));
|
|
|
|
trans->paging_request = subscr_request_conn(trans->vsub,
|
|
|
|
paging_cb_mmsms_est_req,
|
|
|
|
trans, "MT SMS",
|
|
|
|
SGSAP_SERV_IND_SMS);
|
|
|
|
if (!trans->paging_request) {
|
|
|
|
LOGP(DLSMS, LOGL_ERROR, "Failed to initiate Paging "
|
|
|
|
"procedure for %s\n", vlr_subscr_name(trans->vsub));
|
|
|
|
/* Inform SMC about channel establishment failure */
|
|
|
|
gsm411_smc_recv(&trans->sms.smc_inst,
|
|
|
|
GSM411_MMSMS_REL_IND, NULL, 0);
|
|
|
|
trans_free(trans);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prefix msg with a 04.08/04.11 CP header */
|
|
|
|
static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
|
|
|
|
uint8_t msg_type)
|
|
|
|
{
|
|
|
|
struct gsm48_hdr *gh;
|
|
|
|
|
|
|
|
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
|
|
|
|
/* Outgoing needs the highest bit set */
|
|
|
|
gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
|
|
|
|
gh->msg_type = msg_type;
|
|
|
|
OMSC_LINKID_CB(msg) = trans->dlci;
|
|
|
|
|
|
|
|
DEBUGP(DLSMS, "sending CP message (trans=%x)\n", trans->transaction_id);
|
|
|
|
|
|
|
|
return gsm411_sendmsg(trans->conn, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* mm_send: receive MMCCSMS sap message from SMC */
|
|
|
|
static int gsm411_mm_send(struct gsm411_smc_inst *inst, int msg_type,
|
|
|
|
struct msgb *msg, int cp_msg_type)
|
|
|
|
{
|
|
|
|
struct gsm_trans *trans =
|
|
|
|
container_of(inst, struct gsm_trans, sms.smc_inst);
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
switch (msg_type) {
|
|
|
|
case GSM411_MMSMS_EST_REQ:
|
|
|
|
rc = gsm411_mmsms_est_req(trans);
|
|
|
|
msgb_free(msg); /* upper layer does not free msg */
|
|
|
|
break;
|
|
|
|
case GSM411_MMSMS_DATA_REQ:
|
|
|
|
rc = gsm411_cp_sendmsg(msg, trans, cp_msg_type);
|
|
|
|
break;
|
|
|
|
case GSM411_MMSMS_REL_REQ:
|
|
|
|
DEBUGP(DLSMS, "Got MMSMS_REL_REQ, destroying transaction.\n");
|
|
|
|
msgb_free(msg);
|
|
|
|
trans_free(trans);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DLSMS, LOGL_NOTICE, "Unhandled MMCCSMS msg 0x%x\n", msg_type);
|
|
|
|
msgb_free(msg);
|
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* mm_send: receive MNCCSMS sap message from SMR */
|
|
|
|
int gsm411_mn_send(struct gsm411_smr_inst *inst, int msg_type,
|
|
|
|
struct msgb *msg)
|
|
|
|
{
|
|
|
|
struct gsm_trans *trans =
|
|
|
|
container_of(inst, struct gsm_trans, sms.smr_inst);
|
|
|
|
|
|
|
|
/* forward to SMC */
|
|
|
|
return gsm411_smc_send(&trans->sms.smc_inst, msg_type, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm340_rx_sms_submit(struct gsm_sms *gsms)
|
|
|
|
{
|
|
|
|
if (db_sms_store(gsms) != 0) {
|
|
|
|
LOGP(DLSMS, LOGL_ERROR, "Failed to store SMS in Database\n");
|
|
|
|
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
|
|
|
|
}
|
|
|
|
/* dispatch a signal to tell higher level about it */
|
|
|
|
send_signal(S_SMS_SUBMITTED, NULL, gsms, 0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */
|
|
|
|
static int gsm340_gen_oa_sub(uint8_t *oa, unsigned int oa_len,
|
|
|
|
const struct gsm_sms_addr *src)
|
|
|
|
{
|
|
|
|
/* network specific, private numbering plan */
|
|
|
|
return gsm340_gen_oa(oa, oa_len, src->ton, src->npi, src->addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate a msgb containing an 03.40 9.2.2.1 SMS-DELIVER TPDU derived from
|
|
|
|
* struct gsm_sms, returns total size of TPDU */
|
|
|
|
static int gsm340_gen_sms_deliver_tpdu(struct msgb *msg, struct gsm_sms *sms)
|
|
|
|
{
|
|
|
|
uint8_t *smsp;
|
|
|
|
uint8_t oa[12]; /* max len per 03.40 */
|
|
|
|
uint8_t octet_len;
|
|
|
|
unsigned int old_msg_len = msg->len;
|
|
|
|
int oa_len;
|
|
|
|
|
|
|
|
/* generate first octet with masked bits */
|
|
|
|
smsp = msgb_put(msg, 1);
|
|
|
|
/* TP-MTI (message type indicator) */
|
|
|
|
*smsp = GSM340_SMS_DELIVER_SC2MS;
|
|
|
|
/* TP-MMS (more messages to send) */
|
|
|
|
if (0 /* FIXME */)
|
|
|
|
*smsp |= 0x04;
|
|
|
|
/* TP-SRI(deliver)/SRR(submit) */
|
|
|
|
if (sms->status_rep_req)
|
|
|
|
*smsp |= 0x20;
|
|
|
|
/* TP-UDHI (indicating TP-UD contains a header) */
|
|
|
|
if (sms->ud_hdr_ind)
|
|
|
|
*smsp |= 0x40;
|
|
|
|
|
|
|
|
/* generate originator address */
|
|
|
|
oa_len = gsm340_gen_oa_sub(oa, sizeof(oa), &sms->src);
|
|
|
|
if (oa_len < 0)
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
smsp = msgb_put(msg, oa_len);
|
|
|
|
memcpy(smsp, oa, oa_len);
|
|
|
|
|
|
|
|
/* generate TP-PID */
|
|
|
|
smsp = msgb_put(msg, 1);
|
|
|
|
*smsp = sms->protocol_id;
|
|
|
|
|
|
|
|
/* generate TP-DCS */
|
|
|
|
smsp = msgb_put(msg, 1);
|
|
|
|
*smsp = sms->data_coding_scheme;
|
|
|
|
|
|
|
|
/* generate TP-SCTS */
|
|
|
|
smsp = msgb_put(msg, 7);
|
|
|
|
gsm340_gen_scts(smsp, time(NULL));
|
|
|
|
|
|
|
|
/* generate TP-UDL */
|
|
|
|
smsp = msgb_put(msg, 1);
|
|
|
|
*smsp = sms->user_data_len;
|
|
|
|
|
|
|
|
/* generate TP-UD */
|
|
|
|
switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
|
|
|
|
case DCS_7BIT_DEFAULT:
|
|
|
|
octet_len = sms->user_data_len*7/8;
|
|
|
|
if (sms->user_data_len*7%8 != 0)
|
|
|
|
octet_len++;
|
|
|
|
/* Warning, user_data_len indicates the amount of septets
|
|
|
|
* (characters), we need amount of octets occupied */
|
|
|
|
smsp = msgb_put(msg, octet_len);
|
|
|
|
memcpy(smsp, sms->user_data, octet_len);
|
|
|
|
break;
|
|
|
|
case DCS_UCS2:
|
|
|
|
case DCS_8BIT_DATA:
|
|
|
|
smsp = msgb_put(msg, sms->user_data_len);
|
|
|
|
memcpy(smsp, sms->user_data, sms->user_data_len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DLSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n",
|
|
|
|
sms->data_coding_scheme);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return msg->len - old_msg_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* As defined by GSM 03.40, Section 9.2.2.3. */
|
|
|
|
static int gsm340_gen_sms_status_report_tpdu(struct msgb *msg,
|
|
|
|
struct gsm_sms *sms)
|
|
|
|
{
|
|
|
|
unsigned int old_msg_len = msg->len;
|
|
|
|
uint8_t oa[12]; /* max len per 03.40 */
|
|
|
|
uint8_t *smsp;
|
|
|
|
int oa_len;
|
|
|
|
|
|
|
|
/* generate first octet with masked bits */
|
|
|
|
smsp = msgb_put(msg, 1);
|
|
|
|
/* TP-MTI (message type indicator) */
|
|
|
|
*smsp = GSM340_SMS_STATUS_REP_SC2MS;
|
|
|
|
/* TP-MMS (more messages to send) */
|
|
|
|
if (0 /* FIXME */)
|
|
|
|
*smsp |= 0x04;
|
|
|
|
/* TP-MR (message reference) */
|
|
|
|
smsp = msgb_put(msg, 1);
|
|
|
|
*smsp = sms->msg_ref;
|
|
|
|
|
|
|
|
/* generate recipient address */
|
|
|
|
oa_len = gsm340_gen_oa_sub(oa, sizeof(oa), &sms->src);
|
|
|
|
if (oa_len < 0)
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
smsp = msgb_put(msg, oa_len);
|
|
|
|
memcpy(smsp, oa, oa_len);
|
|
|
|
|
|
|
|
/* generate TP-SCTS (Service centre timestamp) */
|
|
|
|
smsp = msgb_put(msg, 7);
|
|
|
|
gsm340_gen_scts(smsp, sms->created);
|
|
|
|
|
|
|
|
/* generate TP-DT (Discharge time, in TP-SCTS format). */
|
|
|
|
smsp = msgb_put(msg, 7);
|
|
|
|
gsm340_gen_scts(smsp, sms->created);
|
|
|
|
|
|
|
|
/* TP-ST (status) */
|
|
|
|
smsp = msgb_put(msg, 1);
|
|
|
|
/* From GSM 03.40, Section 9.2.3.15, 0x00 means OK. */
|
|
|
|
*smsp = 0x00;
|
|
|
|
|
|
|
|
LOGP(DLSMS, LOGL_INFO, "sending status report for SMS reference %x\n",
|
|
|
|
sms->msg_ref);
|
|
|
|
|
|
|
|
return msg->len - old_msg_len;
|
|
|
|
}
|
|
|
|
|
rename gsm_subscriber_connection to ran_conn
In preparation for inter-BSC and inter-MSC handover, we need to separate the
subscriber management logic from the actual RAN connections. What better time
to finally rename gsm_subscriber_connection.
* Name choice:
In 2G, this is a connection to the BSS, but even though 3GPP TS commonly talk
of "BSS-A" and "BSS-B" when explaining handover, it's not good to call it
"bss_conn": in 3G a BSS is called RNS, IIUC.
The overall term for 2G (GERAN) and 3G (UTRAN) is RAN: Radio Access Network.
* Rationale:
A subscriber in the MSC so far has only one RAN connection, but e.g. for
inter-BSC handover, a second one needs to be created to handover to. Most of
the items in the former gsm_subscriber_connection are actually related to the
RAN, with only a few MM and RTP related items. So, as a first step, just rename
it to ran_conn, to cosmetically prepare for moving the not strictly RAN related
items away later.
Also:
- Rename some functions from msc_subscr_conn_* to ran_conn_*
- Rename "Subscr_Conn" FSM instance name to "RAN_conn"
- Rename SUBSCR_CONN_* to RAN_CONN_*
Change-Id: Ic595f7a558d3553c067f77dc67543ab59659707a
4 years ago
|
|
|
static int sms_route_mt_sms(struct ran_conn *conn,
|
|
|
|
struct gsm_sms *gsms)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
#ifdef BUILD_SMPP
|
|
|
|
int smpp_first = smpp_route_smpp_first(gsms, conn);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Route through SMPP first before going to the local database. In case
|
|
|
|
* of a unroutable message and no local subscriber, SMPP will be tried
|
|
|
|
* twice. In case of an unknown subscriber continue with the normal
|
|
|
|
* delivery of the SMS.
|
|
|
|
*/
|
|
|
|
if (smpp_first) {
|
|
|
|
rc = smpp_try_deliver(gsms, conn);
|
|
|
|
if (rc == GSM411_RP_CAUSE_MO_NUM_UNASSIGNED)
|
|
|
|
/* unknown subscriber, try local */
|
|
|
|
goto try_local;
|
|
|
|
if (rc < 0) {
|
|
|
|
LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.",
|
|
|
|
vlr_subscr_name(conn->vsub), rc);
|
|
|
|
rc = GSM411_RP_CAUSE_MO_TEMP_FAIL;
|
|
|
|
/* rc will be logged by gsm411_send_rp_error() */
|
|
|
|
rate_ctr_inc(&conn->network->msc_ctrs->ctr[
|
|
|
|
MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
try_local:
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* determine gsms->receiver based on dialled number */
|
|
|
|
gsms->receiver = vlr_subscr_find_by_msisdn(conn->network->vlr, gsms->dst.addr, VSUB_USE_SMS_RECEIVER);
|
|
|
|
if (!gsms->receiver) {
|
|
|
|
#ifdef BUILD_SMPP
|
|
|
|
/* Avoid a second look-up */
|
|
|
|
if (smpp_first) {
|
|
|
|
rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]);
|
|
|
|
return GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = smpp_try_deliver(gsms, conn);
|
|
|
|
if (rc == GSM411_RP_CAUSE_MO_NUM_UNASSIGNED) {
|
|
|
|
rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]);
|
|
|
|
} else if (rc < 0) {
|
|
|
|
LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.",
|
|
|
|
vlr_subscr_name(conn->vsub), rc);
|
|
|
|
rc = GSM411_RP_CAUSE_MO_TEMP_FAIL;
|
|
|
|
/* rc will be logged by gsm411_send_rp_error() */
|
|
|
|
rate_ctr_inc(&conn->network->msc_ctrs->ctr[
|
|
|
|
MSC_CTR_SMS_DELIVER_UNKNOWN_ERROR]);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
|
|
|
|
rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]);
|
|
|
|
#endif
|
|
|
|
} else
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* process an incoming TPDU (called from RP-DATA)
|
|
|
|
* return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
|
libmsc: send RP-ACK to MS after ESME sends SMPP DELIVER-SM-RESP
Hold on with the GSM 04.11 RP-ACK/RP-ERROR that we send to the MS until
we get a confirmation from the ESME, via SMPP DELIVER-SM-RESP, that we
can route this sms somewhere we can reach indeed.
After this change, the conversation looks like this:
MS GSM 03.40 SMSC SMPP 3.4 ESME
| | |
| SMS-SUBMIT | |
|------------------->| |
| | DELIVER-SM |
| |---------------->|
| | |
| | DELIVER-SM-RESP |
| |<----------------|
| GSM 04.11 RP-ACK | |
|<-------------------| |
| | |
Before this patch, the RP-ACK was sent back straight forward to the MS,
no matter if the sms can be route by the ESME or not. Thus, the user
ends up getting a misleading "message delivered" in their phone screen,
when the message may just be unroutable by the ESME hence silently
dropped.
If we get no reply from the ESME, there is a hardcoded timer that will
expire to send back an RP-ERROR to the MS indicating that network is
out-of-order. Currently this timer is arbitrarily set to 5 seconds. I
found no specific good default value on the SMPP 3.4 specs, section 7.2,
where the response_timer is described. There must be a place that
describes a better default value for this. We could also expose this
timer through VTY for configurability reasons, to be done later.
Given all this needs to happen asyncronously, ie. block the SMSC, this
patch extends the gsm_sms structure with two new fields to annotate
useful information to send the RP-ACK/RP-ERROR back to the MS of origin.
These new fields are:
* the GSM 04.07 transaction id, to look up for the gsm_trans object.
* the GSM 04.11 message reference so the MS of origin can correlate this
response to its original request.
Tested here using python-libsmpp script that replies with
DELIVER_SM_RESP and status code 0x0b (Invalid Destination). I can see
here on my motorola C155 that message cannot be delivered. I have tested
with the success status code in the SMPP DELIVER_SM_RESP too.
Change-Id: I0d5bd5693fed6d4f4bd2951711c7888712507bfd
6 years ago
|
|
|
static int gsm340_rx_tpdu(struct gsm_trans *trans, struct msgb *msg,
|
|
|
|
uint32_t gsm411_msg_ref)
|
|
|
|
{
|
rename gsm_subscriber_connection to ran_conn
In preparation for inter-BSC and inter-MSC handover, we need to separate the
subscriber management logic from the actual RAN connections. What better time
to finally rename gsm_subscriber_connection.
* Name choice:
In 2G, this is a connection to the BSS, but even though 3GPP TS commonly talk
of "BSS-A" and "BSS-B" when explaining handover, it's not good to call it
"bss_conn": in 3G a BSS is called RNS, IIUC.
The overall term for 2G (GERAN) and 3G (UTRAN) is RAN: Radio Access Network.
* Rationale:
A subscriber in the MSC so far has only one RAN connection, but e.g. for
inter-BSC handover, a second one needs to be created to handover to. Most of
the items in the former gsm_subscriber_connection are actually related to the
RAN, with only a few MM and RTP related items. So, as a first step, just rename
it to ran_conn, to cosmetically prepare for moving the not strictly RAN related
items away later.
Also:
- Rename some functions from msc_subscr_conn_* to ran_conn_*
- Rename "Subscr_Conn" FSM instance name to "RAN_conn"
- Rename SUBSCR_CONN_* to RAN_CONN_*
Change-Id: Ic595f7a558d3553c067f77dc67543ab59659707a
4 years ago
|
|
|
struct ran_conn *conn = trans->conn;
|
|
|
|
uint8_t *smsp = msgb_sms(msg);
|
|
|
|
struct gsm_sms *gsms;
|
|
|
|
unsigned int sms_alphabet;
|
|
|
|
uint8_t sms_mti, sms_vpf;
|
|
|
|
uint8_t *sms_vp;
|
|
|
|
uint8_t da_len_bytes;
|
|
|
|
uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]);
|
|
|
|
|
|
|
|
gsms = sms_alloc();
|
|
|
|
if (!gsms)
|
|
|
|
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
|
|
|
|
|
|
|
|
/* invert those fields where 0 means active/present */
|
|
|
|
sms_mti = *smsp & 0x03;
|
|
|
|
sms_vpf = (*smsp & 0x18) >> 3;
|
|
|
|
gsms->status_rep_req = (*smsp & 0x20) >> 5;
|
|
|
|
gsms->ud_hdr_ind = (*smsp & 0x40);
|
|
|
|
/*
|
|
|
|
* Not evaluating MMS (More Messages to Send) because the
|
|
|
|
* lchan stays open anyway.
|
|
|
|
* Not evaluating RP (Reply Path) because we're not aware of its
|
|
|
|
* benefits.
|
|
|
|
*/
|
|
|
|
|
|
|
|
smsp++;
|
|
|
|
gsms->msg_ref = *smsp++;
|
|
|
|
|
libmsc: send RP-ACK to MS after ESME sends SMPP DELIVER-SM-RESP
Hold on with the GSM 04.11 RP-ACK/RP-ERROR that we send to the MS until
we get a confirmation from the ESME, via SMPP DELIVER-SM-RESP, that we
can route this sms somewhere we can reach indeed.
After this change, the conversation looks like this:
MS GSM 03.40 SMSC SMPP 3.4 ESME
| | |
| SMS-SUBMIT | |
|------------------->| |
| | DELIVER-SM |
| |---------------->|
| | |
| | DELIVER-SM-RESP |
| |<----------------|
| GSM 04.11 RP-ACK | |
|<-------------------| |
| | |
Before this patch, the RP-ACK was sent back straight forward to the MS,
no matter if the sms can be route by the ESME or not. Thus, the user
ends up getting a misleading "message delivered" in their phone screen,
when the message may just be unroutable by the ESME hence silently
dropped.
If we get no reply from the ESME, there is a hardcoded timer that will
expire to send back an RP-ERROR to the MS indicating that network is
out-of-order. Currently this timer is arbitrarily set to 5 seconds. I
found no specific good default value on the SMPP 3.4 specs, section 7.2,
where the response_timer is described. There must be a place that
describes a better default value for this. We could also expose this
timer through VTY for configurability reasons, to be done later.
Given all this needs to happen asyncronously, ie. block the SMSC, this
patch extends the gsm_sms structure with two new fields to annotate
useful information to send the RP-ACK/RP-ERROR back to the MS of origin.
These new fields are:
* the GSM 04.07 transaction id, to look up for the gsm_trans object.
* the GSM 04.11 message reference so the MS of origin can correlate this
response to its original request.
Tested here using python-libsmpp script that replies with
DELIVER_SM_RESP and status code 0x0b (Invalid Destination). I can see
here on my motorola C155 that message cannot be delivered. I have tested
with the success status code in the SMPP DELIVER_SM_RESP too.
Change-Id: I0d5bd5693fed6d4f4bd2951711c7888712507bfd
6 years ago
|
|
|
gsms->gsm411.transaction_id = trans->transaction_id;
|
|
|
|
gsms->gsm411.msg_ref = gsm411_msg_ref;
|
|
|
|
|
|
|
|
/* length in bytes of the destination address */
|
|
|
|
da_len_bytes = 2 + *smsp/2 + *smsp%2;
|
|
|
|
if (da_len_bytes > 12) {
|
|
|
|
LOGP(DLSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
|
|
|
|
rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
|
|
|
|
goto out;
|
|
|
|
} else if (da_len_bytes < 4) {
|
|
|
|
LOGP(DLSMS, LOGL_ERROR, "Destination Address < 4 bytes ?!?\n");
|
|
|
|
rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
memset(address_lv, 0, sizeof(address_lv));
|
|
|
|
memcpy(address_lv, smsp, da_len_bytes);
|
|
|
|
/* mangle first byte to reflect length in bytes, not digits */
|
|
|
|
address_lv[0] = da_len_bytes - 1;
|
|
|
|
|
|
|
|
gsms->dst.ton = (address_lv[1] >> 4) & 7;
|
|
|
|
gsms->dst.npi = address_lv[1] & 0xF;
|
|
|
|
/* convert to real number */
|
|
|
|
gsm48_decode_bcd_number(gsms->dst.addr,
|
|
|
|
sizeof(gsms->dst.addr), address_lv, 1);
|
|
|
|
smsp += da_len_bytes;
|
|
|
|
|
|
|
|
gsms->protocol_id = *smsp++;
|
|
|
|
gsms->data_coding_scheme = *smsp++;
|
|
|
|
|
|
|
|
sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
|
|
|
|
if (sms_alphabet == 0xffffffff) {
|
|
|
|
rc = GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (sms_vpf) {
|
|
|
|
case GSM340_TP_VPF_RELATIVE:
|
|
|
|
sms_vp = smsp++;
|
|
|
|
break;
|
|
|
|
case GSM340_TP_VPF_ABSOLUTE:
|
|
|
|
case GSM340_TP_VPF_ENHANCED:
|
|
|
|
sms_vp = smsp;
|
|
|
|
/* the additional functionality indicator... */
|
|
|
|
if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7))
|
|
|
|
smsp++;
|
|
|
|
smsp += 7;
|
|
|
|
break;
|
|
|
|
case GSM340_TP_VPF_NONE:
|
|
|
|
sms_vp = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DLSMS, LOGL_NOTICE,
|
|
|
|
"SMS Validity period not implemented: 0x%02x\n", sms_vpf);
|
|
|
|
rc = GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
gsms->user_data_len = *smsp++;
|
|
|
|
if (gsms->user_data_len) {
|
|
|
|
memcpy(gsms->user_data, smsp, gsms->user_data_len);
|
|
|
|
|
|
|
|
switch (sms_alphabet) {
|
|
|
|
case DCS_7BIT_DEFAULT:
|
|
|
|
gsm_7bit_decode_n(gsms->text, sizeof(gsms->text), smsp,
|
|
|
|
gsms->user_data_len);
|
|
|
|
break;
|
|
|
|
case DCS_8BIT_DATA:
|
|
|
|
case DCS_UCS2:
|
|
|
|
case DCS_NONE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OSMO_STRLCPY_ARRAY(gsms->src.addr, conn->vsub->msisdn);
|
|
|
|
|
|
|
|
LOGP(DLSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
|
|
|
|
"MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
|
|
|
|
"UserDataLength: 0x%02x, UserData: \"%s\"\n",
|
|
|
|
vlr_subscr_name(conn->vsub), sms_mti, sms_vpf, gsms->msg_ref,
|
|
|
|
gsms->protocol_id, gsms->data_coding_scheme, gsms->dst.addr,
|
|
|
|
gsms->user_data_len,
|
|
|
|
sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
|
|
|
|
osmo_hexdump(gsms->user_data, gsms->user_data_len));
|
|
|
|
|
|
|
|
gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
|
|
|
|
|
|
|
|
/* FIXME: This looks very wrong */
|
|
|
|
send_signal(0, NULL, gsms, 0);
|
|
|
|
|
|
|
|
rc = sms_route_mt_sms(conn, gsms);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This SMS got routed through SMPP or no receiver exists.
|
|
|
|
* In any case, we store it in the database for further processing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (sms_mti) {
|
|
|
|
case GSM340_SMS_SUBMIT_MS2SC:
|
|
|
|
/* MS is submitting a SMS */
|
|
|
|
rc = gsm340_rx_sms_submit(gsms);
|
|
|
|
break;
|
|
|
|
case GSM340_SMS_COMMAND_MS2SC:
|
|
|
|
case GSM340_SMS_DELIVER_REP_MS2SC:
|
|
|
|
LOGP(DLSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
|
|
|
|
rc = GSM411_RP_CAUSE_IE_NOTEXIST;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DLSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
|
|
|
|
rc = GSM411_RP_CAUSE_IE_NOTEXIST;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
sms_free(gsms);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prefix msg with a RP-DATA header and send as SMR DATA */
|
|
|
|
static int gsm411_rp_sendmsg(struct gsm411_smr_inst *inst, struct msgb *msg,
|
|
|
|
uint8_t rp_msg_type, uint8_t rp_msg_ref,
|
|
|
|
int rl_msg_type)
|
|
|
|
{
|
|
|
|
struct gsm411_rp_hdr *rp;
|
|
|
|
uint8_t len = msg->len;
|
|
|
|
|
|
|
|
/* GSM 04.11 RP-DATA header */
|
|
|
|
rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
|
|
|
|
rp->len = len + 2;
|
|
|
|
rp->msg_type = rp_msg_type;
|
|
|
|
rp->msg_ref = rp_msg_ref;
|
|
|
|
|
|
|
|
return gsm411_smr_send(inst, rl_msg_type, msg);
|
|
|
|
}
|
|
|
|
|
libmsc: send RP-ACK to MS after ESME sends SMPP DELIVER-SM-RESP
Hold on with the GSM 04.11 RP-ACK/RP-ERROR that we send to the MS until
we get a confirmation from the ESME, via SMPP DELIVER-SM-RESP, that we
can route this sms somewhere we can reach indeed.
After this change, the conversation looks like this:
MS GSM 03.40 SMSC SMPP 3.4 ESME
| | |
| SMS-SUBMIT | |
|------------------->| |
| | DELIVER-SM |
| |---------------->|
| | |
| | DELIVER-SM-RESP |
| |<----------------|
| GSM 04.11 RP-ACK | |
|<-------------------| |
| | |
Before this patch, the RP-ACK was sent back straight forward to the MS,
no matter if the sms can be route by the ESME or not. Thus, the user
ends up getting a misleading "message delivered" in their phone screen,
when the message may just be unroutable by the ESME hence silently
dropped.
If we get no reply from the ESME, there is a hardcoded timer that will
expire to send back an RP-ERROR to the MS indicating that network is
out-of-order. Currently this timer is arbitrarily set to 5 seconds. I
found no specific good default value on the SMPP 3.4 specs, section 7.2,
where the response_timer is described. There must be a place that
describes a better default value for this. We could also expose this
timer through VTY for configurability reasons, to be done later.
Given all this needs to happen asyncronously, ie. block the SMSC, this
patch extends the gsm_sms structure with two new fields to annotate
useful information to send the RP-ACK/RP-ERROR back to the MS of origin.
These new fields are:
* the GSM 04.07 transaction id, to look up for the gsm_trans object.
* the GSM 04.11 message reference so the MS of origin can correlate this
response to its original request.
Tested here using python-libsmpp script that replies with
DELIVER_SM_RESP and status code 0x0b (Invalid Destination). I can see
here on my motorola C155 that message cannot be delivered. I have tested
with the success status code in the SMPP DELIVER_SM_RESP too.
Change-Id: I0d5bd5693fed6d4f4bd2951711c7888712507bfd
6 years ago
|
|
|
int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref)
|
|
|
|
{
|
|
|
|
struct msgb *msg = gsm411_msgb_alloc();
|
|
|
|
|
|
|
|
DEBUGP(DLSMS, "TX: SMS RP ACK\n");
|
|
|
|
|
|
|
|
return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, GSM411_MT_RP_ACK_MT,
|
|
|
|
msg_ref, GSM411_SM_RL_REPORT_REQ);
|
|
|
|
}
|
|
|
|
|
libmsc: send RP-ACK to MS after ESME sends SMPP DELIVER-SM-RESP
Hold on with the GSM 04.11 RP-ACK/RP-ERROR that we send to the MS until
we get a confirmation from the ESME, via SMPP DELIVER-SM-RESP, that we
can route this sms somewhere we can reach indeed.
After this change, the conversation looks like this:
MS GSM 03.40 SMSC SMPP 3.4 ESME
| | |
| SMS-SUBMIT | |
|------------------->| |
| | DELIVER-SM |
| |---------------->|
| | |
| | DELIVER-SM-RESP |
| |<----------------|
| GSM 04.11 RP-ACK | |
|<-------------------| |
| | |
Before this patch, the RP-ACK was sent back straight forward to the MS,
no matter if the sms can be route by the ESME or not. Thus, the user
ends up getting a misleading "message delivered" in their phone screen,
when the message may just be unroutable by the ESME hence silently
dropped.
If we get no reply from the ESME, there is a hardcoded timer that will
expire to send back an RP-ERROR to the MS indicating that network is
out-of-order. Currently this timer is arbitrarily set to 5 seconds. I
found no specific good default value on the SMPP 3.4 specs, section 7.2,
where the response_timer is described. There must be a place that
describes a better default value for this. We could also expose this
timer through VTY for configurability reasons, to be done later.
Given all this needs to happen asyncronously, ie. block the SMSC, this
patch extends the gsm_sms structure with two new fields to annotate
useful information to send the RP-ACK/RP-ERROR back to the MS of origin.
These new fields are:
* the GSM 04.07 transaction id, to look up for the gsm_trans object.
* the GSM 04.11 message reference so the MS of origin can correlate this
response to its original request.
Tested here using python-libsmpp script that replies with
DELIVER_SM_RESP and status code 0x0b (Invalid Destination). I can see
here on my motorola C155 that message cannot be delivered. I have tested
with the success status code in the SMPP DELIVER_SM_RESP too.
Change-Id: I0d5bd5693fed6d4f4bd2951711c7888712507bfd
6 years ago
|
|
|
int gsm411_send_rp_error(struct gsm_trans *trans, uint8_t msg_ref,
|
|
|
|
uint8_t cause)
|
|
|
|
{
|
|
|
|
struct msgb *msg = gsm411_msgb_alloc();
|
|
|
|
|
|
|
|
msgb_tv_put(msg, 1, cause);
|
|
|
|
|
|
|
|
LOGP(DLSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
|
|
|
|
get_value_string(gsm411_rp_cause_strs, cause));
|
|
|
|
|
|
|
|
return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg,
|
|
|
|
GSM411_MT_RP_ERROR_MT, msg_ref, GSM411_SM_RL_REPORT_REQ);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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,
|
|
|
|
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);
|
|