2017-10-16 16:25:45 +00:00
|
|
|
/* Point-to-Point (PP) Short Message Service (SMS).
|
2011-10-28 01:55:37 +00:00
|
|
|
* Support on Mobile Radio Interface
|
2017-06-20 02:35:06 +00:00
|
|
|
* 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>
|
2011-10-28 01:55:37 +00:00
|
|
|
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
|
|
|
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
|
|
|
* (C) 2010 by On-Waves
|
|
|
|
* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
*
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
2017-11-12 16:00:26 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
|
|
*
|
2011-10-28 01:55:37 +00:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
2014-10-26 19:42:49 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
2011-10-28 01:55:37 +00:00
|
|
|
* (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
|
2014-10-26 19:42:49 +00:00
|
|
|
* GNU General Public License for more details.
|
2011-10-28 01:55:37 +00:00
|
|
|
*
|
2014-10-26 19:42:49 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2011-10-28 01:55:37 +00:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Notes on msg:
|
|
|
|
*
|
|
|
|
* Messages from lower layer are freed by lower layer.
|
|
|
|
*
|
|
|
|
* Messages to upper layer are freed after upper layer call returns, so upper
|
|
|
|
* layer cannot use data after returning. Upper layer must not free the msg.
|
|
|
|
*
|
|
|
|
* This implies: Lower layer messages can be forwarded to upper layer.
|
|
|
|
*
|
|
|
|
* Upper layer messages are freed by lower layer, so they must not be freed
|
|
|
|
* after calling lower layer.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Notes on release:
|
|
|
|
*
|
|
|
|
* Whenever the process returns to IDLE, the MM connection is released using
|
|
|
|
* MMSMS-REL-REQ. It is allowed to destroy this process while processing
|
|
|
|
* this message.
|
|
|
|
*
|
2012-11-21 23:33:52 +00:00
|
|
|
* There is an exception, if MMSMS-REL-IND is received from lower layer, the
|
2011-10-28 01:55:37 +00:00
|
|
|
* process returns to IDLE without sending MMSMS-REL-REQ.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-07-30 19:33:48 +00:00
|
|
|
#include <sys/types.h>
|
2012-11-14 05:07:47 +00:00
|
|
|
#include <inttypes.h>
|
2020-07-30 19:33:48 +00:00
|
|
|
#include <string.h>
|
2011-10-28 01:55:37 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/logging.h>
|
|
|
|
#include <osmocom/core/timer.h>
|
|
|
|
|
|
|
|
#include <osmocom/gsm/gsm0411_utils.h>
|
|
|
|
#include <osmocom/gsm/gsm0411_smc.h>
|
|
|
|
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
|
|
|
|
2017-06-12 19:44:18 +00:00
|
|
|
/*! \addtogroup sms
|
|
|
|
* @{
|
2017-10-16 16:25:45 +00:00
|
|
|
* \file gsm0411_smc.c
|
2017-06-19 22:17:59 +00:00
|
|
|
* Point-to-Point (PP) Short Message Service (SMS) as per TS 04.11
|
2017-06-12 19:44:18 +00:00
|
|
|
*/
|
|
|
|
|
2011-10-28 01:55:37 +00:00
|
|
|
static void cp_timer_expired(void *data);
|
|
|
|
|
2011-11-12 22:52:40 +00:00
|
|
|
#define MAX_SMS_RETRY 2
|
2011-10-28 01:55:37 +00:00
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
#define SMC_LOG_STR "SMC(%" PRIu64 ") "
|
|
|
|
|
2011-10-28 01:55:37 +00:00
|
|
|
/* init a new instance */
|
2012-11-14 05:07:47 +00:00
|
|
|
void gsm411_smc_init(struct gsm411_smc_inst *inst, uint64_t id, int network,
|
2011-10-28 01:55:37 +00:00
|
|
|
int (*mn_recv) (struct gsm411_smc_inst *inst, int msg_type,
|
|
|
|
struct msgb *msg),
|
|
|
|
int (*mm_send) (struct gsm411_smc_inst *inst, int msg_type,
|
|
|
|
struct msgb *msg, int cp_msg_type))
|
|
|
|
{
|
|
|
|
memset(inst, 0, sizeof(*inst));
|
2012-11-14 05:07:47 +00:00
|
|
|
inst->id = id;
|
2011-10-28 01:55:37 +00:00
|
|
|
inst->network = network;
|
|
|
|
inst->cp_max_retr = MAX_SMS_RETRY;
|
2011-11-12 22:52:20 +00:00
|
|
|
inst->cp_tc1 = GSM411_TMR_TC1A_SEC / (inst->cp_max_retr + 1);
|
2011-10-28 01:55:37 +00:00
|
|
|
inst->cp_state = GSM411_CPS_IDLE;
|
|
|
|
inst->mn_recv = mn_recv;
|
|
|
|
inst->mm_send = mm_send;
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
2012-12-01 11:51:34 +00:00
|
|
|
SMC_LOG_STR "instance created for %s\n",
|
|
|
|
inst->id, inst->network ? "network" : "mobile");
|
2011-10-28 01:55:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* clear instance */
|
|
|
|
void gsm411_smc_clear(struct gsm411_smc_inst *inst)
|
|
|
|
{
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "clearing instance\n", inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
|
|
|
|
osmo_timer_del(&inst->cp_timer);
|
|
|
|
|
|
|
|
/* free stored msg */
|
|
|
|
if (inst->cp_msg) {
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "dropping pending message\n", inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
inst->cp_msg = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *smc_state_names[] = {
|
|
|
|
"IDLE",
|
|
|
|
"MM_CONN_PENDING",
|
|
|
|
"WAIT_CP_ACK",
|
|
|
|
"MM_ESTABLISHED",
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct value_string gsm411_cp_cause_strs[] = {
|
|
|
|
{ GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
|
|
|
|
{ GSM411_CP_CAUSE_CONGESTION, "Congestion" },
|
|
|
|
{ GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
|
|
|
|
{ GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
|
|
|
|
{ GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
|
|
|
|
{ GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
|
|
|
|
{ GSM411_CP_CAUSE_MSG_INCOMP_STATE,
|
|
|
|
"Message incompatible with protocol state" },
|
|
|
|
{ GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
|
|
|
|
{ GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
|
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void new_cp_state(struct gsm411_smc_inst *inst,
|
|
|
|
enum gsm411_cp_state state)
|
|
|
|
{
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "new CP state %s -> %s\n", inst->id,
|
2011-10-28 01:55:37 +00:00
|
|
|
smc_state_names[inst->cp_state], smc_state_names[state]);
|
|
|
|
inst->cp_state = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm411_tx_cp_error(struct gsm411_smc_inst *inst, uint8_t cause)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg = gsm411_msgb_alloc();
|
|
|
|
uint8_t *causep;
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_NOTICE,
|
|
|
|
SMC_LOG_STR "TX CP-ERROR, cause %d (%s)\n", inst->id, cause,
|
2011-10-28 01:55:37 +00:00
|
|
|
get_value_string(gsm411_cp_cause_strs, cause));
|
|
|
|
|
|
|
|
causep = msgb_put(nmsg, 1);
|
|
|
|
*causep = cause;
|
|
|
|
|
|
|
|
return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
|
|
|
|
GSM411_MT_CP_ERROR);
|
|
|
|
}
|
|
|
|
|
2012-11-13 21:29:35 +00:00
|
|
|
/* establish SMC connection */
|
2011-10-28 01:55:37 +00:00
|
|
|
static int gsm411_mnsms_est_req(struct gsm411_smc_inst *inst, struct msgb *msg)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
|
|
|
if (inst->cp_msg) {
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_FATAL,
|
|
|
|
SMC_LOG_STR "EST REQ, but we already have an "
|
|
|
|
"cp_msg. This should never happen, please fix!\n",
|
|
|
|
inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
inst->cp_msg = msg;
|
|
|
|
new_cp_state(inst, GSM411_CPS_MM_CONN_PENDING);
|
|
|
|
/* clear stored release flag */
|
|
|
|
inst->cp_rel = 0;
|
|
|
|
/* send MMSMS_EST_REQ */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
return inst->mm_send(inst, GSM411_MMSMS_EST_REQ, nmsg, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm411_mmsms_send_msg(struct gsm411_smc_inst *inst)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "send CP data\n", inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
/* reset retry counter */
|
|
|
|
if (inst->cp_state != GSM411_CPS_WAIT_CP_ACK)
|
|
|
|
inst->cp_retx = 0;
|
|
|
|
/* 5.2.3.1.2: enter MO-wait for CP-ACK */
|
|
|
|
/* 5.2.3.2.3: enter MT-wait for CP-ACK */
|
|
|
|
new_cp_state(inst, GSM411_CPS_WAIT_CP_ACK);
|
2017-05-08 16:00:28 +00:00
|
|
|
osmo_timer_setup(&inst->cp_timer, cp_timer_expired, inst);
|
2011-10-28 01:55:37 +00:00
|
|
|
/* 5.3.2.1: Set Timer TC1A */
|
|
|
|
osmo_timer_schedule(&inst->cp_timer, inst->cp_tc1, 0);
|
|
|
|
/* clone cp_msg */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
memcpy(msgb_put(nmsg, inst->cp_msg->len), inst->cp_msg->data,
|
|
|
|
inst->cp_msg->len);
|
|
|
|
/* send MMSMS_DATA_REQ with CP-DATA */
|
|
|
|
return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
|
|
|
|
GSM411_MT_CP_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm411_mmsms_est_cnf(struct gsm411_smc_inst *inst, struct msgb *msg)
|
|
|
|
{
|
|
|
|
if (!inst->cp_msg) {
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_FATAL,
|
|
|
|
SMC_LOG_STR "EST CNF, but we have no cp_msg. This "
|
|
|
|
"should never happen, please fix!\n",
|
|
|
|
inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gsm411_mmsms_send_msg(inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SMC TC1* is expired */
|
|
|
|
static void cp_timer_expired(void *data)
|
|
|
|
{
|
|
|
|
struct gsm411_smc_inst *inst = data;
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
|
|
|
if (inst->cp_retx == inst->cp_max_retr) {
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "TC1* timeout, no more retries.\n",
|
|
|
|
inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
/* 5.3.2.1: enter idle state */
|
|
|
|
new_cp_state(inst, GSM411_CPS_IDLE);
|
|
|
|
/* indicate error */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
|
|
|
|
msgb_free(nmsg);
|
|
|
|
/* free pending stored msg */
|
|
|
|
if (inst->cp_msg) {
|
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
inst->cp_msg = NULL;
|
|
|
|
}
|
|
|
|
/* release MM connection */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "TC1* timeout, retrying...\n", inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
inst->cp_retx++;
|
|
|
|
gsm411_mmsms_est_cnf(inst, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg)
|
|
|
|
{
|
|
|
|
/* free stored msg */
|
|
|
|
if (inst->cp_msg) {
|
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
inst->cp_msg = NULL;
|
|
|
|
}
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "received CP-ACK\n", inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
/* 5.3.2.1 enter MM Connection established */
|
|
|
|
new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
|
|
|
|
/* 5.3.2.1: Reset Timer TC1* */
|
|
|
|
osmo_timer_del(&inst->cp_timer);
|
|
|
|
|
|
|
|
/* pending release? */
|
|
|
|
if (inst->cp_rel) {
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "we have pending release.\n",
|
|
|
|
inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
new_cp_state(inst, GSM411_CPS_IDLE);
|
|
|
|
/* release MM connection */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm411_mmsms_cp_data(struct gsm411_smc_inst *inst, struct msgb *msg)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg;
|
|
|
|
int mt = GSM411_MNSMS_DATA_IND;
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "received CP-DATA\n", inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
/* 5.3.1 enter MM Connection established (if idle) */
|
|
|
|
if (inst->cp_state == GSM411_CPS_IDLE) {
|
|
|
|
new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
|
|
|
|
mt = GSM411_MNSMS_EST_IND;
|
|
|
|
/* clear stored release flag */
|
|
|
|
inst->cp_rel = 0;
|
|
|
|
}
|
|
|
|
/* send MMSMS_DATA_REQ (CP ACK) */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, GSM411_MT_CP_ACK);
|
|
|
|
/* indicate data */
|
|
|
|
inst->mn_recv(inst, mt, msg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* send CP DATA */
|
|
|
|
static int gsm411_mnsms_data_req(struct gsm411_smc_inst *inst, struct msgb *msg)
|
|
|
|
{
|
|
|
|
if (inst->cp_msg) {
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_FATAL,
|
|
|
|
SMC_LOG_STR "DATA REQ, but we already have an "
|
|
|
|
"cp_msg. This should never happen, please fix!\n",
|
|
|
|
inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* store and send */
|
|
|
|
inst->cp_msg = msg;
|
|
|
|
return gsm411_mmsms_send_msg(inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* release SMC connection */
|
|
|
|
static int gsm411_mnsms_rel_req(struct gsm411_smc_inst *inst, struct msgb *msg)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
|
|
|
msgb_free(msg);
|
|
|
|
|
|
|
|
/* discard silently */
|
|
|
|
if (inst->cp_state == GSM411_CPS_IDLE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* store release, until established or released */
|
|
|
|
if (inst->cp_state != GSM411_CPS_MM_ESTABLISHED) {
|
2012-11-11 09:09:24 +00:00
|
|
|
LOGP(DLSMS, LOGL_NOTICE,
|
2012-11-14 05:07:47 +00:00
|
|
|
SMC_LOG_STR "cannot release yet current state: %s\n",
|
|
|
|
inst->id, smc_state_names[inst->cp_state]);
|
2011-10-28 01:55:37 +00:00
|
|
|
inst->cp_rel = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free stored msg */
|
|
|
|
if (inst->cp_msg) {
|
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
inst->cp_msg = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_cp_state(inst, GSM411_CPS_IDLE);
|
|
|
|
/* release MM connection */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm411_mmsms_cp_error(struct gsm411_smc_inst *inst, struct msgb *msg)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
|
|
|
/* free stored msg */
|
|
|
|
if (inst->cp_msg) {
|
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
inst->cp_msg = NULL;
|
|
|
|
}
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "received CP-ERROR\n", inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
/* 5.3.4 enter idle */
|
|
|
|
new_cp_state(inst, GSM411_CPS_IDLE);
|
|
|
|
/* indicate error */
|
|
|
|
inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, msg);
|
|
|
|
/* release MM connection */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gsm411_mmsms_rel_ind(struct gsm411_smc_inst *inst, struct msgb *msg)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
|
|
|
/* free stored msg */
|
|
|
|
if (inst->cp_msg) {
|
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
inst->cp_msg = NULL;
|
|
|
|
}
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "MM layer is released\n", inst->id);
|
2011-10-28 01:55:37 +00:00
|
|
|
/* 5.3.4 enter idle */
|
|
|
|
new_cp_state(inst, GSM411_CPS_IDLE);
|
|
|
|
/* indicate error */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
|
|
|
|
msgb_free(nmsg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* abort SMC connection */
|
|
|
|
static int gsm411_mnsms_abort_req(struct gsm411_smc_inst *inst,
|
|
|
|
struct msgb *msg)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
|
|
|
/* free stored msg */
|
|
|
|
if (inst->cp_msg) {
|
|
|
|
msgb_free(inst->cp_msg);
|
|
|
|
inst->cp_msg = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 5.3.4 go idle */
|
|
|
|
new_cp_state(inst, GSM411_CPS_IDLE);
|
|
|
|
/* send MMSMS_DATA_REQ with CP-ERROR */
|
|
|
|
inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, msg, GSM411_MT_CP_ERROR);
|
|
|
|
/* release MM connection */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* statefull handling for MNSMS SAP messages */
|
2012-11-22 09:50:52 +00:00
|
|
|
static const struct smcdownstate {
|
2011-10-28 01:55:37 +00:00
|
|
|
uint32_t states;
|
|
|
|
int type;
|
|
|
|
const char *name;
|
|
|
|
int (*rout) (struct gsm411_smc_inst *inst,
|
|
|
|
struct msgb *msg);
|
|
|
|
} smcdownstatelist[] = {
|
|
|
|
/* establish request */
|
|
|
|
{SBIT(GSM411_CPS_IDLE),
|
|
|
|
GSM411_MNSMS_EST_REQ,
|
|
|
|
"MNSMS-EST-REQ", gsm411_mnsms_est_req},
|
|
|
|
|
|
|
|
/* release request */
|
|
|
|
{ALL_STATES,
|
|
|
|
GSM411_MNSMS_REL_REQ,
|
|
|
|
"MNSMS-REL-REQ", gsm411_mnsms_rel_req},
|
|
|
|
|
|
|
|
/* data request */
|
|
|
|
{SBIT(GSM411_CPS_MM_ESTABLISHED),
|
|
|
|
GSM411_MNSMS_DATA_REQ,
|
|
|
|
"MNSMS-DATA-REQ", gsm411_mnsms_data_req},
|
|
|
|
|
|
|
|
/* abort request */
|
|
|
|
{ALL_STATES - SBIT(GSM411_CPS_IDLE),
|
|
|
|
GSM411_MNSMS_ABORT_REQ,
|
|
|
|
"MNSMS-ABORT-REQ", gsm411_mnsms_abort_req},
|
|
|
|
};
|
|
|
|
|
|
|
|
#define SMCDOWNSLLEN \
|
|
|
|
(sizeof(smcdownstatelist) / sizeof(struct smcdownstate))
|
|
|
|
|
|
|
|
/* message from upper layer */
|
|
|
|
int gsm411_smc_send(struct gsm411_smc_inst *inst, int msg_type,
|
|
|
|
struct msgb *msg)
|
|
|
|
{
|
|
|
|
int i, rc;
|
|
|
|
|
|
|
|
/* find function for current state and message */
|
|
|
|
for (i = 0; i < SMCDOWNSLLEN; i++) {
|
|
|
|
if ((msg_type == smcdownstatelist[i].type)
|
|
|
|
&& (SBIT(inst->cp_state) & smcdownstatelist[i].states))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == SMCDOWNSLLEN) {
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_NOTICE,
|
|
|
|
SMC_LOG_STR "message %u unhandled at this state %s.\n",
|
|
|
|
inst->id, msg_type, smc_state_names[inst->cp_state]);
|
2011-10-28 01:55:37 +00:00
|
|
|
msgb_free(msg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "message %s received in state %s\n", inst->id,
|
2011-10-28 01:55:37 +00:00
|
|
|
smcdownstatelist[i].name, smc_state_names[inst->cp_state]);
|
|
|
|
|
|
|
|
rc = smcdownstatelist[i].rout(inst, msg);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* statefull handling for MMSMS SAP messages */
|
2012-11-22 09:50:52 +00:00
|
|
|
static const struct smcdatastate {
|
2011-10-28 01:55:37 +00:00
|
|
|
uint32_t states;
|
|
|
|
int type, cp_type;
|
|
|
|
const char *name;
|
|
|
|
int (*rout) (struct gsm411_smc_inst *inst,
|
|
|
|
struct msgb *msg);
|
|
|
|
} smcdatastatelist[] = {
|
|
|
|
/* establish confirm */
|
|
|
|
{SBIT(GSM411_CPS_MM_CONN_PENDING),
|
|
|
|
GSM411_MMSMS_EST_CNF, 0,
|
|
|
|
"MMSMS-EST-CNF", gsm411_mmsms_est_cnf},
|
|
|
|
|
|
|
|
/* establish indication (CP DATA) */
|
|
|
|
{SBIT(GSM411_CPS_IDLE),
|
|
|
|
GSM411_MMSMS_EST_IND, GSM411_MT_CP_DATA,
|
|
|
|
"MMSMS-EST-IND (CP DATA)", gsm411_mmsms_cp_data},
|
|
|
|
|
|
|
|
/* data indication (CP DATA) */
|
|
|
|
{SBIT(GSM411_CPS_MM_ESTABLISHED),
|
|
|
|
GSM411_MMSMS_DATA_IND, GSM411_MT_CP_DATA,
|
|
|
|
"MMSMS-DATA-IND (CP DATA)", gsm411_mmsms_cp_data},
|
|
|
|
|
|
|
|
/* data indication (CP ACK) */
|
|
|
|
{SBIT(GSM411_CPS_WAIT_CP_ACK),
|
|
|
|
GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ACK,
|
|
|
|
"MMSMS-DATA-IND (CP ACK)", gsm411_mmsms_cp_ack},
|
|
|
|
|
|
|
|
/* data indication (CP ERROR) */
|
|
|
|
{ALL_STATES,
|
|
|
|
GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ERROR,
|
|
|
|
"MMSMS-DATA-IND (CP_ERROR)", gsm411_mmsms_cp_error},
|
|
|
|
|
|
|
|
/* release indication */
|
|
|
|
{ALL_STATES - SBIT(GSM411_CPS_IDLE),
|
|
|
|
GSM411_MMSMS_REL_IND, 0,
|
|
|
|
"MMSMS-REL-IND", gsm411_mmsms_rel_ind},
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
#define SMCDATASLLEN \
|
|
|
|
(sizeof(smcdatastatelist) / sizeof(struct smcdatastate))
|
|
|
|
|
|
|
|
/* message from lower layer
|
|
|
|
* WARNING: We must not free msg, since it will be performed by the
|
|
|
|
* lower layer. */
|
|
|
|
int gsm411_smc_recv(struct gsm411_smc_inst *inst, int msg_type,
|
|
|
|
struct msgb *msg, int cp_msg_type)
|
|
|
|
{
|
|
|
|
int i, rc;
|
|
|
|
|
|
|
|
/* find function for current state and message */
|
|
|
|
for (i = 0; i < SMCDATASLLEN; i++) {
|
2012-11-21 23:33:52 +00:00
|
|
|
/* state must match, MM message must match
|
2011-10-28 01:55:37 +00:00
|
|
|
* CP msg must match only in case of MMSMS_DATA_IND
|
|
|
|
*/
|
|
|
|
if ((msg_type == smcdatastatelist[i].type)
|
|
|
|
&& (SBIT(inst->cp_state) & smcdatastatelist[i].states)
|
|
|
|
&& (msg_type != GSM411_MMSMS_DATA_IND
|
|
|
|
|| cp_msg_type == smcdatastatelist[i].cp_type))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == SMCDATASLLEN) {
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_NOTICE,
|
|
|
|
SMC_LOG_STR "message 0x%x/%u unhandled at this "
|
|
|
|
"state %s.\n", inst->id, msg_type, cp_msg_type,
|
2011-10-28 01:55:37 +00:00
|
|
|
smc_state_names[inst->cp_state]);
|
|
|
|
if (msg_type == GSM411_MMSMS_EST_IND
|
|
|
|
|| msg_type == GSM411_MMSMS_DATA_IND) {
|
|
|
|
struct msgb *nmsg;
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_NOTICE,
|
|
|
|
SMC_LOG_STR "RX Unimplemented CP "
|
|
|
|
"msg_type: 0x%02x\n", inst->id, msg_type);
|
2011-10-28 01:55:37 +00:00
|
|
|
/* 5.3.4 enter idle */
|
|
|
|
new_cp_state(inst, GSM411_CPS_IDLE);
|
|
|
|
/* indicate error */
|
|
|
|
gsm411_tx_cp_error(inst,
|
|
|
|
GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
|
|
|
|
/* send error indication to upper layer */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
|
|
|
|
msgb_free(nmsg);
|
|
|
|
/* release MM connection */
|
|
|
|
nmsg = gsm411_msgb_alloc();
|
|
|
|
return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-14 05:07:47 +00:00
|
|
|
LOGP(DLSMS, LOGL_INFO,
|
|
|
|
SMC_LOG_STR "message %s received in state %s\n", inst->id,
|
2011-10-28 01:55:37 +00:00
|
|
|
smcdatastatelist[i].name, smc_state_names[inst->cp_state]);
|
|
|
|
|
|
|
|
rc = smcdatastatelist[i].rout(inst, msg);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2017-06-12 19:44:18 +00:00
|
|
|
|
2018-01-24 15:50:11 +00:00
|
|
|
const struct value_string gsm411_cp_state_names[] = {
|
|
|
|
{ GSM411_CPS_IDLE, "IDLE" },
|
|
|
|
{ GSM411_CPS_MM_CONN_PENDING, "MM_CONN_PENDING" },
|
|
|
|
{ GSM411_CPS_WAIT_CP_ACK, "WAIT_CP_ACK" },
|
|
|
|
{ GSM411_CPS_MM_ESTABLISHED, "ESTABLISHD" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
2017-06-12 19:44:18 +00:00
|
|
|
/*! @} */
|