<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/20625">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">BSSMAP RESET: generalize a_reset FSM<br><br>Separate the a_reset FSM implementation from BSSMAP and MSC specifics, so that<br>it can be re-used on the Lb interface.<br><br>Move the FSM implementation to reset.c and tweak, to match common practices we<br>have generally established in our osmo_fsm implementations.<br><br>Keep a_reset.h and a_reset.c and redirect to reset.c.<br><br>A difficulty is setting a proper logging category: the FSM definition allows<br>only one fixed logging category for FSM state transitions and events. Ideally,<br>the BSSMAP reset fsm would log on DMSC, and the BSSMAP-LE reset fsm would log<br>on DLCS. Since that is not possible, introduce a separate DRESET logging<br>category. This in fact matches an item on my wishlist, because if a given MSC<br>is configured but currently not connected, the previous RESET FSM would<br>continuously "spam" log LOGL_NOTICE messages indicating that it is resending<br>RESET, and I often want to silence those messages without silencing the entire<br>DMSC category. This is now easily possible by setting DRESET logging to<br>LOGL_ERROR. There is additional "link up" / "link lost" logging on DMSC, so all<br>interesting info is still visible on DMSC.<br><br>Change-Id: Ib3c3a163186c40a93be0dea666230431172136df<br>---<br>M include/osmocom/bsc/Makefile.am<br>M include/osmocom/bsc/a_reset.h<br>M include/osmocom/bsc/bsc_msc_data.h<br>M include/osmocom/bsc/debug.h<br>M include/osmocom/bsc/osmo_bsc_sigtran.h<br>A include/osmocom/bsc/reset.h<br>M src/osmo-bsc/Makefile.am<br>M src/osmo-bsc/a_reset.c<br>M src/osmo-bsc/osmo_bsc_main.c<br>M src/osmo-bsc/osmo_bsc_sigtran.c<br>A src/osmo-bsc/reset.c<br>M tests/handover/handover_test.c<br>12 files changed, 283 insertions(+), 190 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/25/20625/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am</span><br><span>index 8c42287..ed7fd6e 100644</span><br><span>--- a/include/osmocom/bsc/Makefile.am</span><br><span>+++ b/include/osmocom/bsc/Makefile.am</span><br><span>@@ -48,6 +48,7 @@</span><br><span>     paging.h \</span><br><span>   pcu_if.h \</span><br><span>   pcuif_proto.h \</span><br><span style="color: hsl(120, 100%, 40%);">+       reset.h \</span><br><span>    rest_octets.h \</span><br><span>      rs232.h \</span><br><span>    signal.h \</span><br><span>diff --git a/include/osmocom/bsc/a_reset.h b/include/osmocom/bsc/a_reset.h</span><br><span>index 46a392f..dd44ea5 100644</span><br><span>--- a/include/osmocom/bsc/a_reset.h</span><br><span>+++ b/include/osmocom/bsc/a_reset.h</span><br><span>@@ -23,7 +23,7 @@</span><br><span> struct bsc_msc_data;</span><br><span> </span><br><span> /* Create and start state machine which handles the reset/reset-ack procedure */</span><br><span style="color: hsl(0, 100%, 40%);">-void a_reset_alloc(struct bsc_msc_data *msc, const char *name, void *cb);</span><br><span style="color: hsl(120, 100%, 40%);">+void a_reset_alloc(struct bsc_msc_data *msc, const char *name);</span><br><span> </span><br><span> /* Confirm that we successfully received a reset acknowledge message */</span><br><span> void a_reset_ack_confirm(struct bsc_msc_data *msc);</span><br><span>diff --git a/include/osmocom/bsc/bsc_msc_data.h b/include/osmocom/bsc/bsc_msc_data.h</span><br><span>index 5699b77..7077cc3 100644</span><br><span>--- a/include/osmocom/bsc/bsc_msc_data.h</span><br><span>+++ b/include/osmocom/bsc/bsc_msc_data.h</span><br><span>@@ -171,7 +171,7 @@</span><br><span> </span><br><span>               /* Pointer to the osmo-fsm that controls the</span><br><span>                  * BSSMAP RESET procedure */</span><br><span style="color: hsl(0, 100%, 40%);">-            struct osmo_fsm_inst *reset_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct reset *reset;</span><br><span>         } a;</span><br><span> </span><br><span>     uint32_t x_osmo_ign;</span><br><span>diff --git a/include/osmocom/bsc/debug.h b/include/osmocom/bsc/debug.h</span><br><span>index 0380b74..4ad61b4 100644</span><br><span>--- a/include/osmocom/bsc/debug.h</span><br><span>+++ b/include/osmocom/bsc/debug.h</span><br><span>@@ -28,6 +28,7 @@</span><br><span>    DAS,</span><br><span>         DCBS,</span><br><span>        DLCS,</span><br><span style="color: hsl(120, 100%, 40%);">+ DRESET,</span><br><span>      Debug_LastEntry,</span><br><span> };</span><br><span> </span><br><span>diff --git a/include/osmocom/bsc/osmo_bsc_sigtran.h b/include/osmocom/bsc/osmo_bsc_sigtran.h</span><br><span>index faaceb2..79afa6b 100644</span><br><span>--- a/include/osmocom/bsc/osmo_bsc_sigtran.h</span><br><span>+++ b/include/osmocom/bsc/osmo_bsc_sigtran.h</span><br><span>@@ -40,6 +40,8 @@</span><br><span> /* Close all open sigtran connections and channels */</span><br><span> void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_bsc_sigtran_tx_reset(const struct bsc_msc_data *msc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Send reset-ack to MSC */</span><br><span> void osmo_bsc_sigtran_tx_reset_ack(const struct bsc_msc_data *msc);</span><br><span> </span><br><span>diff --git a/include/osmocom/bsc/reset.h b/include/osmocom/bsc/reset.h</span><br><span>new file mode 100644</span><br><span>index 0000000..1eb5435</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/bsc/reset.h</span><br><span>@@ -0,0 +1,27 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Manage RESET and disconnection detectoin on BSSMAP and BSSMAP-LE */</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum reset_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+ RESET_EV_RX_RESET_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+        RESET_EV_CONN_CFM_SUCCESS,</span><br><span style="color: hsl(120, 100%, 40%);">+    RESET_EV_CONN_CFM_FAILURE,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct reset_cfg {</span><br><span style="color: hsl(120, 100%, 40%);">+  int conn_cfm_failure_threshold;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              void (*tx_reset)(void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+         void (*link_up)(void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+          void (*link_lost)(void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+        } ops;</span><br><span style="color: hsl(120, 100%, 40%);">+        void *data;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct reset {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct reset_cfg cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ int conn_cfm_failures;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct reset *reset_alloc(void *ctx, const char *label, const struct reset_cfg *cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+bool reset_is_conn_ready(const struct reset *reset);</span><br><span>diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am</span><br><span>index 8d109fd..45c1f0f 100644</span><br><span>--- a/src/osmo-bsc/Makefile.am</span><br><span>+++ b/src/osmo-bsc/Makefile.am</span><br><span>@@ -89,6 +89,7 @@</span><br><span>   paging.c \</span><br><span>   pcu_sock.c \</span><br><span>         penalty_timers.c \</span><br><span style="color: hsl(120, 100%, 40%);">+    reset.c \</span><br><span>    rest_octets.c \</span><br><span>      system_information.c \</span><br><span>       timeslot_fsm.c \</span><br><span>diff --git a/src/osmo-bsc/a_reset.c b/src/osmo-bsc/a_reset.c</span><br><span>index 9446d13..b385dad 100644</span><br><span>--- a/src/osmo-bsc/a_reset.c</span><br><span>+++ b/src/osmo-bsc/a_reset.c</span><br><span>@@ -18,183 +18,57 @@</span><br><span>  *</span><br><span>  */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/logging.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/utils.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/timer.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/fsm.h></span><br><span> #include <osmocom/core/signal.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <unistd.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <errno.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/signal.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <osmocom/bsc/debug.h></span><br><span> #include <osmocom/bsc/bsc_msc_data.h></span><br><span> #include <osmocom/bsc/osmo_bsc_sigtran.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/bsc/signal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/reset.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define RESET_RESEND_INTERVAL 2          /* sec */</span><br><span style="color: hsl(0, 100%, 40%);">-#define RESET_RESEND_TIMER_NO 4                /* See also 3GPP TS 48.008 Chapter 3.1.4.1.3.1 */</span><br><span style="color: hsl(0, 100%, 40%);">-#define BAD_CONNECTION_THRESOLD 3      /* connection failures */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Reset context data (callbacks, state machine etc...) */</span><br><span style="color: hsl(0, 100%, 40%);">-struct reset_ctx {</span><br><span style="color: hsl(0, 100%, 40%);">-   /* Connection failure counter. When this counter</span><br><span style="color: hsl(0, 100%, 40%);">-         * reaches a certain threshold, the reset procedure</span><br><span style="color: hsl(0, 100%, 40%);">-      * will be triggered */</span><br><span style="color: hsl(0, 100%, 40%);">- int conn_loss_counter;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* Callback function to be called when a connection</span><br><span style="color: hsl(0, 100%, 40%);">-      * failure is detected and a rest must occur */</span><br><span style="color: hsl(0, 100%, 40%);">- void (*cb)(void *priv);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Privated data for the callback function */</span><br><span style="color: hsl(0, 100%, 40%);">-   void *priv;</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-enum reset_fsm_states {</span><br><span style="color: hsl(0, 100%, 40%);">-    ST_DISC,                /* Disconnected from remote end */</span><br><span style="color: hsl(0, 100%, 40%);">-      ST_CONN,                /* We have a confirmed connection */</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-enum reset_fsm_evt {</span><br><span style="color: hsl(0, 100%, 40%);">-      EV_RESET_ACK,           /* got reset acknowlegement from remote end */</span><br><span style="color: hsl(0, 100%, 40%);">-  EV_N_DISCONNECT,        /* lost a connection */</span><br><span style="color: hsl(0, 100%, 40%);">- EV_N_CONNECT,           /* made a successful connection */</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static const struct value_string fsm_event_names[] = {</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_VALUE_STRING(EV_RESET_ACK),</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_VALUE_STRING(EV_N_DISCONNECT),</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_VALUE_STRING(EV_N_CONNECT),</span><br><span style="color: hsl(0, 100%, 40%);">-        {0, NULL}</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Disconnected state event handler */</span><br><span style="color: hsl(0, 100%, 40%);">-static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+static void a_reset_tx_reset(void *data)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(reset_ctx);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- reset_ctx->conn_loss_counter = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct bsc_msc_data *msc = data;</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_bsc_sigtran_tx_reset(msc);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Called when entering Disconnected state */</span><br><span style="color: hsl(0, 100%, 40%);">-static void fsm_disc_onenter_cb(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+static void a_reset_link_up(void *data)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct bsc_msc_data *msc = reset_ctx->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  LOGPFSML(fi, LOGL_NOTICE, "BSSMAP MSC assocation is down, reconnecting...\n");</span><br><span style="color: hsl(0, 100%, 40%);">-        if (prev_state != ST_DISC) {</span><br><span style="color: hsl(0, 100%, 40%);">-            osmo_stat_item_dec(msc->msc_statg->items[MSC_STAT_MSC_LINKS_ACTIVE], 1);</span><br><span style="color: hsl(0, 100%, 40%);">-          osmo_signal_dispatch(SS_MSC, S_MSC_LOST, msc);</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bsc_msc_data *msc = data;</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGP(DMSC, LOGL_NOTICE, "(msc%d) BSSMAP assocation is up\n", msc->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_stat_item_inc(msc->msc_statg->items[MSC_STAT_MSC_LINKS_ACTIVE], 1);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_signal_dispatch(SS_MSC, S_MSC_CONNECTED, msc);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Connected state event handler */</span><br><span style="color: hsl(0, 100%, 40%);">-static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+static void a_reset_link_lost(void *data)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(reset_ctx);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (event) {</span><br><span style="color: hsl(0, 100%, 40%);">-        case EV_N_DISCONNECT:</span><br><span style="color: hsl(0, 100%, 40%);">-           if (reset_ctx->conn_loss_counter >= BAD_CONNECTION_THRESOLD)</span><br><span style="color: hsl(0, 100%, 40%);">-                      osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);</span><br><span style="color: hsl(0, 100%, 40%);">-             else</span><br><span style="color: hsl(0, 100%, 40%);">-                    reset_ctx->conn_loss_counter++;</span><br><span style="color: hsl(0, 100%, 40%);">-              break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case EV_N_CONNECT:</span><br><span style="color: hsl(0, 100%, 40%);">-              reset_ctx->conn_loss_counter = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case EV_RESET_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-              LOGPFSML(fi, LOGL_INFO, "Received a duplicated BSSMAP RESET ACK, ignoring\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bsc_msc_data *msc = data;</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGP(DMSC, LOGL_NOTICE, "(msc%d) BSSMAP assocation is down\n", msc->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_stat_item_dec(msc->msc_statg->items[MSC_STAT_MSC_LINKS_ACTIVE], 1);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_signal_dispatch(SS_MSC, S_MSC_LOST, msc);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_bsc_sigtran_reset(msc);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Called when entering Connected state */</span><br><span style="color: hsl(0, 100%, 40%);">-static void fsm_conn_onenter_cb(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct bsc_msc_data *msc = reset_ctx->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  LOGPFSML(fi, LOGL_NOTICE, "BSSMAP MSC assocation is up.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-  if (prev_state != ST_CONN) {</span><br><span style="color: hsl(0, 100%, 40%);">-            osmo_stat_item_inc(msc->msc_statg->items[MSC_STAT_MSC_LINKS_ACTIVE], 1);</span><br><span style="color: hsl(0, 100%, 40%);">-          osmo_signal_dispatch(SS_MSC, S_MSC_CONNECTED, msc);</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Timer callback to retransmit the reset signal */</span><br><span style="color: hsl(0, 100%, 40%);">-static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(reset_ctx);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPFSML(fi, LOGL_NOTICE, "(re)sending BSSMAP RESET message...\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   reset_ctx->cb(reset_ctx->priv);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);</span><br><span style="color: hsl(0, 100%, 40%);">-     return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct osmo_fsm_state reset_fsm_states[] = {</span><br><span style="color: hsl(0, 100%, 40%);">-   [ST_DISC] = {</span><br><span style="color: hsl(0, 100%, 40%);">-                .in_event_mask = (1 << EV_RESET_ACK),</span><br><span style="color: hsl(0, 100%, 40%);">-                     .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),</span><br><span style="color: hsl(0, 100%, 40%);">-                  .name = "DISC",</span><br><span style="color: hsl(0, 100%, 40%);">-               .action = fsm_disc_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-                  .onenter = fsm_disc_onenter_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-                 },</span><br><span style="color: hsl(0, 100%, 40%);">- [ST_CONN] = {</span><br><span style="color: hsl(0, 100%, 40%);">-                .in_event_mask = (1 << EV_N_DISCONNECT) | (1 << EV_N_CONNECT) | (1 << EV_RESET_ACK),</span><br><span style="color: hsl(0, 100%, 40%);">-                  .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),</span><br><span style="color: hsl(0, 100%, 40%);">-                  .name = "CONN",</span><br><span style="color: hsl(0, 100%, 40%);">-               .action = fsm_conn_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-                  .onenter = fsm_conn_onenter_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-                 },</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* State machine definition */</span><br><span style="color: hsl(0, 100%, 40%);">-static struct osmo_fsm fsm = {</span><br><span style="color: hsl(0, 100%, 40%);">-   .name = "A-RESET",</span><br><span style="color: hsl(0, 100%, 40%);">-    .states = reset_fsm_states,</span><br><span style="color: hsl(0, 100%, 40%);">-     .num_states = ARRAY_SIZE(reset_fsm_states),</span><br><span style="color: hsl(0, 100%, 40%);">-     .log_subsys = DMSC,</span><br><span style="color: hsl(0, 100%, 40%);">-     .timer_cb = fsm_reset_ack_timeout_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-   .event_names = fsm_event_names,</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Create and start state machine which handles the reset/reset-ack procedure */</span><br><span style="color: hsl(0, 100%, 40%);">-void a_reset_alloc(struct bsc_msc_data *msc, const char *name, void *cb)</span><br><span style="color: hsl(120, 100%, 40%);">+void a_reset_alloc(struct bsc_msc_data *msc, const char *name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      struct reset_ctx *reset_ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct osmo_fsm_inst *reset_fsm;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(msc);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(name);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(cb);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct reset_cfg cfg = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .conn_cfm_failure_threshold = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+              .ops = {</span><br><span style="color: hsl(120, 100%, 40%);">+                      .tx_reset = a_reset_tx_reset,</span><br><span style="color: hsl(120, 100%, 40%);">+                 .link_up = a_reset_link_up,</span><br><span style="color: hsl(120, 100%, 40%);">+                   .link_lost = a_reset_link_lost,</span><br><span style="color: hsl(120, 100%, 40%);">+               },</span><br><span style="color: hsl(120, 100%, 40%);">+            .data = msc,</span><br><span style="color: hsl(120, 100%, 40%);">+  };</span><br><span> </span><br><span>       /* There must not be any double allocation! */</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(msc->a.reset_fsm == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (msc->a.reset) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMSC, LOGL_ERROR, "(msc%d) will not allocate a second reset FSM for this MSC\n", msc->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Allocate and configure a new fsm instance */</span><br><span style="color: hsl(0, 100%, 40%);">- reset_ctx = talloc_zero(msc, struct reset_ctx);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(reset_ctx);</span><br><span style="color: hsl(0, 100%, 40%);">- reset_ctx->priv = msc;</span><br><span style="color: hsl(0, 100%, 40%);">-       reset_ctx->cb = cb;</span><br><span style="color: hsl(0, 100%, 40%);">-  reset_ctx->conn_loss_counter = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    reset_fsm = osmo_fsm_inst_alloc(&fsm, msc, reset_ctx, LOGL_DEBUG, name);</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(reset_fsm);</span><br><span style="color: hsl(0, 100%, 40%);">- msc->a.reset_fsm = reset_fsm;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* Immediately (1ms) kick off reset sending mechanism */</span><br><span style="color: hsl(0, 100%, 40%);">-        osmo_fsm_inst_state_chg_ms(reset_fsm, ST_DISC, 1, RESET_RESEND_TIMER_NO);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Count the new MSC link */</span><br><span style="color: hsl(0, 100%, 40%);">-    osmo_stat_item_inc(msc->msc_statg->items[MSC_STAT_MSC_LINKS_TOTAL], 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ msc->a.reset = reset_alloc(msc, name, &cfg);</span><br><span> }</span><br><span> </span><br><span> /* Confirm that we successfully received a reset acknowledge message */</span><br><span>@@ -203,10 +77,10 @@</span><br><span>       if (!msc)</span><br><span>            return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if (!msc->a.reset_fsm)</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msc->a.reset)</span><br><span>                return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_fsm_inst_dispatch(msc->a.reset_fsm, EV_RESET_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fsm_inst_dispatch(msc->a.reset->fi, RESET_EV_RX_RESET_ACK, NULL);</span><br><span> }</span><br><span> </span><br><span> /* Report a failed connection */</span><br><span>@@ -215,10 +89,10 @@</span><br><span>     if (!msc)</span><br><span>            return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if (!msc->a.reset_fsm)</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msc->a.reset)</span><br><span>                return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_fsm_inst_dispatch(msc->a.reset_fsm, EV_N_DISCONNECT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fsm_inst_dispatch(msc->a.reset->fi, RESET_EV_CONN_CFM_FAILURE, NULL);</span><br><span> }</span><br><span> </span><br><span> /* Report a successful connection */</span><br><span>@@ -227,10 +101,10 @@</span><br><span>    if (!msc)</span><br><span>            return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if (!msc->a.reset_fsm)</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msc->a.reset)</span><br><span>                return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_fsm_inst_dispatch(msc->a.reset_fsm, EV_N_CONNECT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fsm_inst_dispatch(msc->a.reset->fi, RESET_EV_CONN_CFM_SUCCESS, NULL);</span><br><span> }</span><br><span> </span><br><span> /* Check if we have a connection to a specified msc */</span><br><span>@@ -239,16 +113,8 @@</span><br><span>   if (!msc)</span><br><span>            return false;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       if (!msc->a.reset_fsm)</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msc->a.reset)</span><br><span>                return false;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       if (msc->a.reset_fsm->state == ST_CONN)</span><br><span style="color: hsl(0, 100%, 40%);">-           return true;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return false;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static __attribute__((constructor)) void a_reset_fsm_init()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(osmo_fsm_register(&fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        return reset_is_conn_ready(msc->a.reset);</span><br><span> }</span><br><span>diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c</span><br><span>index 26d32d1..35ddbbf 100644</span><br><span>--- a/src/osmo-bsc/osmo_bsc_main.c</span><br><span>+++ b/src/osmo-bsc/osmo_bsc_main.c</span><br><span>@@ -795,6 +795,11 @@</span><br><span>                .description = "Location Services",</span><br><span>                .enabled = 1, .loglevel = LOGL_NOTICE,</span><br><span>       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [DRESET] = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .name = "DRESET",</span><br><span style="color: hsl(120, 100%, 40%);">+           .description = "RESET/ACK on A and Lb interfaces",</span><br><span style="color: hsl(120, 100%, 40%);">+          .enabled = 1, .loglevel = LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span> };</span><br><span> </span><br><span> static int filter_fn(const struct log_context *ctx, struct log_target *tar)</span><br><span>diff --git a/src/osmo-bsc/osmo_bsc_sigtran.c b/src/osmo-bsc/osmo_bsc_sigtran.c</span><br><span>index 6853fac..75b3b58 100644</span><br><span>--- a/src/osmo-bsc/osmo_bsc_sigtran.c</span><br><span>+++ b/src/osmo-bsc/osmo_bsc_sigtran.c</span><br><span>@@ -80,7 +80,7 @@</span><br><span> }</span><br><span> </span><br><span> /* Send reset to MSC */</span><br><span style="color: hsl(0, 100%, 40%);">-static void osmo_bsc_sigtran_tx_reset(const struct bsc_msc_data *msc)</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_bsc_sigtran_tx_reset(const struct bsc_msc_data *msc)</span><br><span> {</span><br><span>       struct osmo_ss7_instance *ss7;</span><br><span>       struct msgb *msg;</span><br><span>@@ -434,18 +434,6 @@</span><br><span>     }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Callback function: Close all open connections */</span><br><span style="color: hsl(0, 100%, 40%);">-static void osmo_bsc_sigtran_reset_cb(const void *priv)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   struct bsc_msc_data *msc = (struct bsc_msc_data*) priv;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Shut down all ongoing traffic */</span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_bsc_sigtran_reset(msc);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* Send reset to MSC */</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_bsc_sigtran_tx_reset(msc);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Default point-code to be used as local address (BSC) */</span><br><span> #define BSC_DEFAULT_PC "0.23.3"</span><br><span> </span><br><span>@@ -619,7 +607,7 @@</span><br><span>                                return -EINVAL;</span><br><span> </span><br><span>                  /* Start MSC-Reset procedure */</span><br><span style="color: hsl(0, 100%, 40%);">-                 a_reset_alloc(msc, msc_name, osmo_bsc_sigtran_reset_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+                      a_reset_alloc(msc, msc_name);</span><br><span>                }</span><br><span>    }</span><br><span> </span><br><span>diff --git a/src/osmo-bsc/reset.c b/src/osmo-bsc/reset.c</span><br><span>new file mode 100644</span><br><span>index 0000000..b5ddc42</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bsc/reset.c</span><br><span>@@ -0,0 +1,198 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Authors: Philipp Maier, Neels Hofmeyr</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/reset.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm reset_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum reset_fsm_state {</span><br><span style="color: hsl(120, 100%, 40%);">+    RESET_ST_DISC,</span><br><span style="color: hsl(120, 100%, 40%);">+        RESET_ST_CONN,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct value_string reset_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(RESET_EV_RX_RESET_ACK),</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_VALUE_STRING(RESET_EV_CONN_CFM_FAILURE),</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(RESET_EV_CONN_CFM_SUCCESS),</span><br><span style="color: hsl(120, 100%, 40%);">+ {}</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct osmo_tdef_state_timeout reset_timeouts[32] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  [RESET_ST_DISC] = { .T = 4 },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define reset_fsm_state_chg(FI, STATE) \</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_tdef_fsm_inst_state_chg(FI, STATE, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                  reset_timeouts, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                     (bsc_gsmnet)->T_defs, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                    5)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct reset *reset_alloc(void *ctx, const char *label, const struct reset_cfg *cfg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct reset *reset;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   fi = osmo_fsm_inst_alloc(&reset_fsm, ctx, NULL, LOGL_DEBUG, label);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    reset = talloc_zero(fi, struct reset);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(reset);</span><br><span style="color: hsl(120, 100%, 40%);">+   *reset = (struct reset){</span><br><span style="color: hsl(120, 100%, 40%);">+              .fi = fi,</span><br><span style="color: hsl(120, 100%, 40%);">+             .cfg = *cfg,</span><br><span style="color: hsl(120, 100%, 40%);">+  };</span><br><span style="color: hsl(120, 100%, 40%);">+    fi->priv = reset;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Immediately (1ms) kick off reset sending mechanism */</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fsm_inst_state_chg_ms(fi, RESET_ST_DISC, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  return reset;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void link_up(struct reset *reset)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGPFSML(reset->fi, LOGL_NOTICE, "link up\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   reset->conn_cfm_failures = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (reset->cfg.ops.link_up)</span><br><span style="color: hsl(120, 100%, 40%);">+                reset->cfg.ops.link_up(reset->cfg.data);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void link_lost(struct reset *reset)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGPFSML(reset->fi, LOGL_NOTICE, "link lost\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reset->cfg.ops.link_lost)</span><br><span style="color: hsl(120, 100%, 40%);">+              reset->cfg.ops.link_lost(reset->cfg.data);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void tx_reset(struct reset *reset)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (reset->cfg.ops.tx_reset)</span><br><span style="color: hsl(120, 100%, 40%);">+               reset->cfg.ops.tx_reset(reset->cfg.data);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void reset_disc_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct reset *reset = (struct reset*)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (prev_state == RESET_ST_CONN)</span><br><span style="color: hsl(120, 100%, 40%);">+              link_lost(reset);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void reset_disc_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        reset_fsm_state_chg(fi, RESET_ST_CONN);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void reset_conn_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct reset *reset = (struct reset*)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (prev_state != RESET_ST_CONN)</span><br><span style="color: hsl(120, 100%, 40%);">+              link_up(reset);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void reset_conn_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct reset *reset = (struct reset*)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    case RESET_EV_RX_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPFSML(fi, LOGL_INFO, "Ignoring duplicate RESET ACK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case RESET_EV_CONN_CFM_FAILURE:</span><br><span style="color: hsl(120, 100%, 40%);">+               reset->conn_cfm_failures++;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (reset->conn_cfm_failures > reset->cfg.conn_cfm_failure_threshold)</span><br><span style="color: hsl(120, 100%, 40%);">+                        reset_fsm_state_chg(fi, RESET_ST_DISC);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case RESET_EV_CONN_CFM_SUCCESS:</span><br><span style="color: hsl(120, 100%, 40%);">+               reset->conn_cfm_failures = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(false);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int reset_fsm_timer_cb(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct reset *reset = (struct reset*)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   tx_reset(reset);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* (re-)enter disconnect state to resend RESET after timeout. */</span><br><span style="color: hsl(120, 100%, 40%);">+      reset_fsm_state_chg(fi, RESET_ST_DISC);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Return 0 to not terminate the fsm */</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define S(x) (1 << (x))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm_state reset_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  [RESET_ST_DISC] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "DISC",</span><br><span style="color: hsl(120, 100%, 40%);">+                     .in_event_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                            | S(RESET_EV_RX_RESET_ACK)</span><br><span style="color: hsl(120, 100%, 40%);">+                            ,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                           | S(RESET_ST_DISC)</span><br><span style="color: hsl(120, 100%, 40%);">+                            | S(RESET_ST_CONN)</span><br><span style="color: hsl(120, 100%, 40%);">+                            ,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .onenter = reset_disc_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = reset_disc_action,</span><br><span style="color: hsl(120, 100%, 40%);">+                  },</span><br><span style="color: hsl(120, 100%, 40%);">+       [RESET_ST_CONN] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "CONN",</span><br><span style="color: hsl(120, 100%, 40%);">+                     .in_event_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                            | S(RESET_EV_RX_RESET_ACK)</span><br><span style="color: hsl(120, 100%, 40%);">+                            | S(RESET_EV_CONN_CFM_FAILURE)</span><br><span style="color: hsl(120, 100%, 40%);">+                        | S(RESET_EV_CONN_CFM_SUCCESS)</span><br><span style="color: hsl(120, 100%, 40%);">+                        ,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                           | S(RESET_ST_DISC)</span><br><span style="color: hsl(120, 100%, 40%);">+                            | S(RESET_ST_CONN)</span><br><span style="color: hsl(120, 100%, 40%);">+                            ,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .onenter = reset_conn_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = reset_conn_action,</span><br><span style="color: hsl(120, 100%, 40%);">+                  },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm reset_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .name = "reset",</span><br><span style="color: hsl(120, 100%, 40%);">+    .states = reset_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+   .num_states = ARRAY_SIZE(reset_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+   .log_subsys = DRESET,</span><br><span style="color: hsl(120, 100%, 40%);">+ .timer_cb = reset_fsm_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+       .event_names = reset_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool reset_is_conn_ready(const struct reset *reset)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return reset->fi->state == RESET_ST_CONN;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute__((constructor)) void a_reset_fsm_init()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(osmo_fsm_register(&reset_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c</span><br><span>index d3f29e1..12f0cc2 100644</span><br><span>--- a/tests/handover/handover_test.c</span><br><span>+++ b/tests/handover/handover_test.c</span><br><span>@@ -1815,3 +1815,7 @@</span><br><span> enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection *conn,</span><br><span>                                              struct gsm_lchan *lchan) { return HO_RESULT_OK; }</span><br><span> void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn) {}</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_bsc_sigtran_tx_reset(void) {}</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_bsc_sigtran_reset(void) {}</span><br><span style="color: hsl(120, 100%, 40%);">+void reset_alloc(void) {}</span><br><span style="color: hsl(120, 100%, 40%);">+void reset_is_conn_ready(void) {}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/20625">change 20625</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-bsc/+/20625"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ib3c3a163186c40a93be0dea666230431172136df </div>
<div style="display:none"> Gerrit-Change-Number: 20625 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>