blob: d6d4a1c5ea0c8b774ffb392f5e98551653d1e551 [file] [log] [blame]
Philipp Maierfbf66102017-04-09 12:32:51 +02001/* (C) 2017 by sysmocom s.f.m.c. GmbH
2 * All Rights Reserved
3 *
4 * Author: Philipp Maier
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <osmocom/core/logging.h>
22#include <osmocom/core/utils.h>
23#include <osmocom/core/timer.h>
24#include <osmocom/core/fsm.h>
25#include <unistd.h>
26#include <errno.h>
27#include <string.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020028#include <osmocom/msc/debug.h>
Harald Welte4bd35d42018-01-25 00:26:59 +010029#include <osmocom/msc/a_reset.h>
Neels Hofmeyr79921222018-11-30 01:46:51 +010030#include <osmocom/msc/msc_common.h>
Philipp Maierfbf66102017-04-09 12:32:51 +020031
Philipp Maierf913e5f2018-05-07 10:15:49 +020032#define RESET_RESEND_INTERVAL 2 /* sec */
33#define RESET_RESEND_TIMER_NO 16 /* See also 3GPP TS 48.008 Chapter 3.1.4.1.3.2 */
Philipp Maierfbf66102017-04-09 12:32:51 +020034
Philipp Maierf913e5f2018-05-07 10:15:49 +020035enum reset_fsm_states {
Philipp Maierfbf66102017-04-09 12:32:51 +020036 ST_DISC, /* Disconnected from remote end */
37 ST_CONN, /* We have a confirmed connection */
38};
39
Philipp Maierf913e5f2018-05-07 10:15:49 +020040enum reset_fsm_evt {
41 EV_CONN_ACK, /* Received either BSSMAP RESET or BSSMAP RESET
42 * ACK from the remote end */
43};
44
45/* Reset context data (callbacks, state machine etc...) */
46struct reset_ctx {
47 /* Callback function to be called when a connection
48 * failure is detected and a rest must occur */
49 void (*cb)(void *priv);
50
51 /* Privated data for the callback function */
52 void *priv;
Philipp Maierfbf66102017-04-09 12:32:51 +020053};
54
Philipp Maier58616782018-02-26 12:40:27 +010055static const struct value_string fsm_event_names[] = {
Philipp Maierf913e5f2018-05-07 10:15:49 +020056 OSMO_VALUE_STRING(EV_CONN_ACK),
Philipp Maier58616782018-02-26 12:40:27 +010057 {0, NULL}
58};
59
Philipp Maierfbf66102017-04-09 12:32:51 +020060/* Disconnected state */
61static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
62{
Philipp Maierfbf66102017-04-09 12:32:51 +020063 osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0);
64}
65
Philipp Maierfbf66102017-04-09 12:32:51 +020066/* Timer callback to retransmit the reset signal */
67static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi)
68{
Philipp Maierf913e5f2018-05-07 10:15:49 +020069 struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;
70 LOGPFSML(fi, LOGL_NOTICE, "(re)sending BSSMAP RESET message...\n");
71 reset_ctx->cb(reset_ctx->priv);
Philipp Maierfbf66102017-04-09 12:32:51 +020072 osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
73 return 0;
74}
75
Philipp Maierf913e5f2018-05-07 10:15:49 +020076static struct osmo_fsm_state reset_fsm_states[] = {
Philipp Maierfbf66102017-04-09 12:32:51 +020077 [ST_DISC] = {
Philipp Maierf913e5f2018-05-07 10:15:49 +020078 .in_event_mask = (1 << EV_CONN_ACK),
79 .out_state_mask = (1 << ST_CONN) | (1 << ST_DISC),
Philipp Maierfbf66102017-04-09 12:32:51 +020080 .name = "DISC",
81 .action = fsm_disc_cb,
82 },
83 [ST_CONN] = {
Philipp Maierf913e5f2018-05-07 10:15:49 +020084 .in_event_mask = (1 << EV_CONN_ACK),
Philipp Maierfbf66102017-04-09 12:32:51 +020085 .name = "CONN",
Philipp Maierfbf66102017-04-09 12:32:51 +020086 },
87};
88
89/* State machine definition */
90static struct osmo_fsm fsm = {
Harald Welte6556d3cb2017-10-25 03:28:03 +020091 .name = "A-RESET",
Philipp Maierf913e5f2018-05-07 10:15:49 +020092 .states = reset_fsm_states,
93 .num_states = ARRAY_SIZE(reset_fsm_states),
Philipp Maierfbf66102017-04-09 12:32:51 +020094 .log_subsys = DMSC,
95 .timer_cb = fsm_reset_ack_timeout_cb,
Philipp Maier58616782018-02-26 12:40:27 +010096 .event_names = fsm_event_names,
Philipp Maierfbf66102017-04-09 12:32:51 +020097};
98
99/* Create and start state machine which handles the reset/reset-ack procedure */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200100struct osmo_fsm_inst *a_reset_alloc(void *ctx, const char *name, void *cb,
101 void *priv, bool already_connected)
Philipp Maierfbf66102017-04-09 12:32:51 +0200102{
103 OSMO_ASSERT(name);
104
Philipp Maierf913e5f2018-05-07 10:15:49 +0200105 struct reset_ctx *reset_ctx;
106 struct osmo_fsm_inst *reset_fsm;
Philipp Maierfbf66102017-04-09 12:32:51 +0200107
108 /* Register the fsm description (if not already done) */
109 if (osmo_fsm_find_by_name(fsm.name) != &fsm)
110 osmo_fsm_register(&fsm);
111
112 /* Allocate and configure a new fsm instance */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200113 reset_ctx = talloc_zero(ctx, struct reset_ctx);
114 OSMO_ASSERT(reset_ctx);
115 reset_ctx->priv = priv;
116 reset_ctx->cb = cb;
117 reset_fsm = osmo_fsm_inst_alloc(&fsm, ctx, reset_ctx, LOGL_DEBUG, name);
118 OSMO_ASSERT(reset_fsm);
Philipp Maierfbf66102017-04-09 12:32:51 +0200119
Harald Welteb6777fb2018-02-08 23:59:19 +0100120 if (already_connected)
Philipp Maierf913e5f2018-05-07 10:15:49 +0200121 osmo_fsm_inst_state_chg(reset_fsm, ST_CONN, 0, 0);
Harald Welteb6777fb2018-02-08 23:59:19 +0100122 else {
123 /* kick off reset-ack sending mechanism */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200124 osmo_fsm_inst_state_chg(reset_fsm, ST_DISC, RESET_RESEND_INTERVAL,
Harald Welteb6777fb2018-02-08 23:59:19 +0100125 RESET_RESEND_TIMER_NO);
126 }
Philipp Maierfbf66102017-04-09 12:32:51 +0200127
Philipp Maierf913e5f2018-05-07 10:15:49 +0200128 return reset_fsm;
Philipp Maierfbf66102017-04-09 12:32:51 +0200129}
130
131/* Confirm that we sucessfully received a reset acknowlege message */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200132void a_reset_ack_confirm(struct osmo_fsm_inst *reset_fsm)
Philipp Maierfbf66102017-04-09 12:32:51 +0200133{
Philipp Maierf913e5f2018-05-07 10:15:49 +0200134 OSMO_ASSERT(reset_fsm);
135 osmo_fsm_inst_dispatch(reset_fsm, EV_CONN_ACK, NULL);
Philipp Maierfbf66102017-04-09 12:32:51 +0200136}
137
138/* Check if we have a connection to a specified msc */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200139bool a_reset_conn_ready(struct osmo_fsm_inst *reset_fsm)
Philipp Maierfbf66102017-04-09 12:32:51 +0200140{
141 /* If no reset context is supplied, we assume that
142 * the connection can't be ready! */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200143 if (!reset_fsm)
Philipp Maierfbf66102017-04-09 12:32:51 +0200144 return false;
145
Philipp Maierf913e5f2018-05-07 10:15:49 +0200146 if (reset_fsm->state == ST_CONN)
Philipp Maierfbf66102017-04-09 12:32:51 +0200147 return true;
148
149 return false;
150}