blob: 1e35a108caac2794d38ef624b12b6d6dfb77b7a8 [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>
Philipp Maierfbf66102017-04-09 12:32:51 +020030
Philipp Maierf913e5f2018-05-07 10:15:49 +020031#define RESET_RESEND_INTERVAL 2 /* sec */
32#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 +020033
Philipp Maierf913e5f2018-05-07 10:15:49 +020034enum reset_fsm_states {
Philipp Maierfbf66102017-04-09 12:32:51 +020035 ST_DISC, /* Disconnected from remote end */
36 ST_CONN, /* We have a confirmed connection */
37};
38
Philipp Maierf913e5f2018-05-07 10:15:49 +020039enum reset_fsm_evt {
40 EV_CONN_ACK, /* Received either BSSMAP RESET or BSSMAP RESET
41 * ACK from the remote end */
42};
43
44/* Reset context data (callbacks, state machine etc...) */
45struct reset_ctx {
46 /* Callback function to be called when a connection
47 * failure is detected and a rest must occur */
48 void (*cb)(void *priv);
49
50 /* Privated data for the callback function */
51 void *priv;
Philipp Maierfbf66102017-04-09 12:32:51 +020052};
53
Philipp Maier58616782018-02-26 12:40:27 +010054static const struct value_string fsm_event_names[] = {
Philipp Maierf913e5f2018-05-07 10:15:49 +020055 OSMO_VALUE_STRING(EV_CONN_ACK),
Philipp Maier58616782018-02-26 12:40:27 +010056 {0, NULL}
57};
58
Philipp Maierfbf66102017-04-09 12:32:51 +020059/* Disconnected state */
60static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
61{
Philipp Maierfbf66102017-04-09 12:32:51 +020062 osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0);
63}
64
Philipp Maierfbf66102017-04-09 12:32:51 +020065/* Timer callback to retransmit the reset signal */
66static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi)
67{
Philipp Maierf913e5f2018-05-07 10:15:49 +020068 struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;
69 LOGPFSML(fi, LOGL_NOTICE, "(re)sending BSSMAP RESET message...\n");
70 reset_ctx->cb(reset_ctx->priv);
Philipp Maierfbf66102017-04-09 12:32:51 +020071 osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
72 return 0;
73}
74
Philipp Maierf913e5f2018-05-07 10:15:49 +020075static struct osmo_fsm_state reset_fsm_states[] = {
Philipp Maierfbf66102017-04-09 12:32:51 +020076 [ST_DISC] = {
Philipp Maierf913e5f2018-05-07 10:15:49 +020077 .in_event_mask = (1 << EV_CONN_ACK),
78 .out_state_mask = (1 << ST_CONN) | (1 << ST_DISC),
Philipp Maierfbf66102017-04-09 12:32:51 +020079 .name = "DISC",
80 .action = fsm_disc_cb,
81 },
82 [ST_CONN] = {
Philipp Maierf913e5f2018-05-07 10:15:49 +020083 .in_event_mask = (1 << EV_CONN_ACK),
Philipp Maierfbf66102017-04-09 12:32:51 +020084 .name = "CONN",
Philipp Maierfbf66102017-04-09 12:32:51 +020085 },
86};
87
88/* State machine definition */
89static struct osmo_fsm fsm = {
Harald Welte6556d3cb2017-10-25 03:28:03 +020090 .name = "A-RESET",
Philipp Maierf913e5f2018-05-07 10:15:49 +020091 .states = reset_fsm_states,
92 .num_states = ARRAY_SIZE(reset_fsm_states),
Philipp Maierfbf66102017-04-09 12:32:51 +020093 .log_subsys = DMSC,
94 .timer_cb = fsm_reset_ack_timeout_cb,
Philipp Maier58616782018-02-26 12:40:27 +010095 .event_names = fsm_event_names,
Philipp Maierfbf66102017-04-09 12:32:51 +020096};
97
98/* Create and start state machine which handles the reset/reset-ack procedure */
Philipp Maierf913e5f2018-05-07 10:15:49 +020099struct osmo_fsm_inst *a_reset_alloc(void *ctx, const char *name, void *cb,
100 void *priv, bool already_connected)
Philipp Maierfbf66102017-04-09 12:32:51 +0200101{
102 OSMO_ASSERT(name);
103
Philipp Maierf913e5f2018-05-07 10:15:49 +0200104 struct reset_ctx *reset_ctx;
105 struct osmo_fsm_inst *reset_fsm;
Philipp Maierfbf66102017-04-09 12:32:51 +0200106
107 /* Register the fsm description (if not already done) */
108 if (osmo_fsm_find_by_name(fsm.name) != &fsm)
109 osmo_fsm_register(&fsm);
110
111 /* Allocate and configure a new fsm instance */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200112 reset_ctx = talloc_zero(ctx, struct reset_ctx);
113 OSMO_ASSERT(reset_ctx);
114 reset_ctx->priv = priv;
115 reset_ctx->cb = cb;
116 reset_fsm = osmo_fsm_inst_alloc(&fsm, ctx, reset_ctx, LOGL_DEBUG, name);
117 OSMO_ASSERT(reset_fsm);
Philipp Maierfbf66102017-04-09 12:32:51 +0200118
Harald Welteb6777fb2018-02-08 23:59:19 +0100119 if (already_connected)
Philipp Maierf913e5f2018-05-07 10:15:49 +0200120 osmo_fsm_inst_state_chg(reset_fsm, ST_CONN, 0, 0);
Harald Welteb6777fb2018-02-08 23:59:19 +0100121 else {
122 /* kick off reset-ack sending mechanism */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200123 osmo_fsm_inst_state_chg(reset_fsm, ST_DISC, RESET_RESEND_INTERVAL,
Harald Welteb6777fb2018-02-08 23:59:19 +0100124 RESET_RESEND_TIMER_NO);
125 }
Philipp Maierfbf66102017-04-09 12:32:51 +0200126
Philipp Maierf913e5f2018-05-07 10:15:49 +0200127 return reset_fsm;
Philipp Maierfbf66102017-04-09 12:32:51 +0200128}
129
130/* Confirm that we sucessfully received a reset acknowlege message */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200131void a_reset_ack_confirm(struct osmo_fsm_inst *reset_fsm)
Philipp Maierfbf66102017-04-09 12:32:51 +0200132{
Philipp Maierf913e5f2018-05-07 10:15:49 +0200133 OSMO_ASSERT(reset_fsm);
134 osmo_fsm_inst_dispatch(reset_fsm, EV_CONN_ACK, NULL);
Philipp Maierfbf66102017-04-09 12:32:51 +0200135}
136
137/* Check if we have a connection to a specified msc */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200138bool a_reset_conn_ready(struct osmo_fsm_inst *reset_fsm)
Philipp Maierfbf66102017-04-09 12:32:51 +0200139{
140 /* If no reset context is supplied, we assume that
141 * the connection can't be ready! */
Philipp Maierf913e5f2018-05-07 10:15:49 +0200142 if (!reset_fsm)
Philipp Maierfbf66102017-04-09 12:32:51 +0200143 return false;
144
Philipp Maierf913e5f2018-05-07 10:15:49 +0200145 if (reset_fsm->state == ST_CONN)
Philipp Maierfbf66102017-04-09 12:32:51 +0200146 return true;
147
148 return false;
149}