summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2017-06-06 14:31:36 +0200
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-06-18 17:50:08 +0200
commit8b0d8a97fb5cddb718c0b35af02bbcfe4599bdc5 (patch)
treed81ce0f11db4ae55542fd702132f3b89c4b3cef8
parentfabe468dd47ffd72a3ff2b6387422d304b178665 (diff)
osmo-bsc: Handle RESET/RESET-ACK properly
Improve the way the BSC executes its RESET/RESET-ACK sequence. Currently only a simple bool variable serves as a state holder. We set this variable to true when we receive the RESET-ACK message. Unfortunately no further checking is done. This patch replaces the old mechanism with a more elaborated implementation which also detects a loss of the connection and makes sure to reconnect properly afterwards. Also the all open connections are closed on connection loss
-rw-r--r--openbsc/include/openbsc/Makefile.am1
-rw-r--r--openbsc/include/openbsc/bsc_msc.h4
-rw-r--r--openbsc/include/openbsc/bsc_msc_data.h1
-rw-r--r--openbsc/include/openbsc/osmo_bsc_reset.h34
-rw-r--r--openbsc/include/openbsc/osmo_bsc_sigtran.h8
-rw-r--r--openbsc/src/libmsc/a_iface.c28
-rw-r--r--openbsc/src/libmsc/a_iface_bssap.c3
-rw-r--r--openbsc/src/osmo-bsc/Makefile.am1
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_bssap.c14
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_reset.c190
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_sigtran.c119
11 files changed, 349 insertions, 54 deletions
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index be75958..e1ae6d2 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -67,6 +67,7 @@ noinst_HEADERS = \
openbscdefines.h \
osmo_bsc.h \
osmo_bsc_grace.h \
+ osmo_bsc_reset.h \
osmo_bsc_rf.h \
osmo_msc.h \
osmo_bsc_sigtran.h \
diff --git a/openbsc/include/openbsc/bsc_msc.h b/openbsc/include/openbsc/bsc_msc.h
index 8b9553b..1b1c2d8 100644
--- a/openbsc/include/openbsc/bsc_msc.h
+++ b/openbsc/include/openbsc/bsc_msc.h
@@ -61,7 +61,9 @@ struct bsc_msc_connection {
struct osmo_sccp_addr g_calling_addr;
struct osmo_sccp_addr g_called_addr;
struct osmo_timer_list msc_reset_timer;
- bool reset_ack;
+ struct osmo_fsm_inst *fsm_reset;
+ unsigned int msc_conn_loss_count;
+
int conn_id_counter;
};
diff --git a/openbsc/include/openbsc/bsc_msc_data.h b/openbsc/include/openbsc/bsc_msc_data.h
index a819aba..0d7ec22 100644
--- a/openbsc/include/openbsc/bsc_msc_data.h
+++ b/openbsc/include/openbsc/bsc_msc_data.h
@@ -38,6 +38,7 @@
#include <osmocom/sigtran/sccp_helpers.h>
#include <osmocom/sigtran/protocol/sua.h>
#include <osmocom/sigtran/protocol/m3ua.h>
+#include <osmocom/core/fsm.h>
#include <regex.h>
diff --git a/openbsc/include/openbsc/osmo_bsc_reset.h b/openbsc/include/openbsc/osmo_bsc_reset.h
new file mode 100644
index 0000000..578f763
--- /dev/null
+++ b/openbsc/include/openbsc/osmo_bsc_reset.h
@@ -0,0 +1,34 @@
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * 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/>.
+ *
+ */
+
+/* Create and start state machine which handles the reset/reset-ack procedure */
+void start_reset_fsm(struct bsc_msc_data *msc);
+
+/* Confirm that we sucessfully received a reset acknowlege message */
+void reset_ack_confirm(struct bsc_msc_data *msc);
+
+/* Report a failed connection */
+void report_conn_fail(struct bsc_msc_data *msc);
+
+/* Report a successful connection */
+void report_conn_success(struct bsc_msc_data *msc);
+
+/* Check if we have a connection to a specified msc */
+bool sccp_conn_ready(struct bsc_msc_data *msc);
diff --git a/openbsc/include/openbsc/osmo_bsc_sigtran.h b/openbsc/include/openbsc/osmo_bsc_sigtran.h
index 37085b6..c57783d 100644
--- a/openbsc/include/openbsc/osmo_bsc_sigtran.h
+++ b/openbsc/include/openbsc/osmo_bsc_sigtran.h
@@ -20,6 +20,8 @@
#pragma once
+#include <openbsc/bsc_msc_data.h>
+
/* Allocate resources to make a new connection oriented sigtran connection
* (not the connection ittself!) */
enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc);
@@ -35,5 +37,11 @@ int osmo_bsc_sigtran_send(struct osmo_bsc_sccp_con *conn, struct msgb *msg);
* locally, when a connection is closed by the MSC */
int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *sccp);
+/* Send reset to MSC */
+void osmo_bsc_sigtran_tx_reset(struct bsc_msc_data *msc);
+
+/* close all open connections */
+void osmo_bsc_sigtran_reset(struct bsc_msc_data *msc);
+
/* Initalize osmo sigtran backhaul */
int osmo_bsc_sigtran_init(struct llist_head *mscs);
diff --git a/openbsc/src/libmsc/a_iface.c b/openbsc/src/libmsc/a_iface.c
index 9ff1b48..ffde21d 100644
--- a/openbsc/src/libmsc/a_iface.c
+++ b/openbsc/src/libmsc/a_iface.c
@@ -36,6 +36,7 @@
#include <openbsc/transaction.h>
#include <openbsc/mgcpgw_client.h>
#include <osmocom/core/byteswap.h>
+#include <osmocom/sccp/sccp_types.h>
#define SSN_BSSAP 254 /* SCCP_SSN_BSSAP */
#define SENDER_PC 1 /* Our local point code */
@@ -292,6 +293,26 @@ int a_assign(struct gsm_trans *trans)
return osmo_sccp_tx_data_msg(conn->a.scu, conn->a.conn_id, msg);
}
+/* Check if we already know this BSC from a successfuly executed reset procedure. */
+static bool test_bsc_known(struct osmo_sccp_addr *bsc_addr)
+{
+ struct a_bsc_addr *addr;
+ struct llist_head *bsc_addr_list = get_bsc_addr_list();
+
+ /* Check if the given address is */
+ llist_for_each_entry(addr, bsc_addr_list, list) {
+ if (memcmp(&addr->calling_addr, bsc_addr, sizeof(*bsc_addr)) == 0) {
+ LOGP(DMSC, LOGL_ERROR, "The calling BSC (%s) is known by this MSC, proceeding...\n",
+ osmo_sccp_addr_dump(bsc_addr));
+ return true;
+ }
+ }
+
+ LOGP(DMSC, LOGL_ERROR, "The calling BSC (%s) is unknown to this MSC, rejecting...\n",
+ osmo_sccp_addr_dump(bsc_addr));
+ return false;
+}
+
/* Callback function, called by the SSCP stack when data arrives */
static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
{
@@ -308,6 +329,13 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
a_conn_info.conn_id = scu_prim->u.connect.conn_id;
a_conn_info.called_addr = &scu_prim->u.connect.called_addr;
a_conn_info.calling_addr = &scu_prim->u.connect.calling_addr;
+
+ if (test_bsc_known(a_conn_info.calling_addr) == false) {
+ rc = osmo_sccp_tx_disconn(scu, a_conn_info.conn_id, a_conn_info.called_addr,
+ SCCP_RETURN_CAUSE_UNQUALIFIED);
+ break;
+ }
+
osmo_sccp_tx_conn_resp(scu, scu_prim->u.connect.conn_id, &scu_prim->u.connect.called_addr, NULL, 0);
if (msgb_l2len(oph->msg) > 0) {
LOGP(DMSC, LOGL_DEBUG, "N-CONNECT.ind(%u, %s)\n",
diff --git a/openbsc/src/libmsc/a_iface_bssap.c b/openbsc/src/libmsc/a_iface_bssap.c
index eafc4e4..9a0706d 100644
--- a/openbsc/src/libmsc/a_iface_bssap.c
+++ b/openbsc/src/libmsc/a_iface_bssap.c
@@ -105,7 +105,8 @@ static void bssmap_handle_reset(struct osmo_sccp_user *scu, struct a_conn_info *
/* Check if we know this BSC already, if yes, refresh its item */
llist_for_each_entry(known_addr, &bsc_addr_list, list) {
- if (memcmp(&known_addr->calling_addr, a_conn_info->calling_addr, sizeof(*a_conn_info->calling_addr)) == 0) {
+ if (memcmp(&known_addr->calling_addr, a_conn_info->calling_addr, sizeof(*a_conn_info->calling_addr)) ==
+ 0) {
LOGP(DMSC, LOGL_NOTICE, "This BSC is already known to this MSC, refreshing its list item\n");
llist_del(&known_addr->list);
talloc_free(known_addr);
diff --git a/openbsc/src/osmo-bsc/Makefile.am b/openbsc/src/osmo-bsc/Makefile.am
index d0d0e3a..32e2cee 100644
--- a/openbsc/src/osmo-bsc/Makefile.am
+++ b/openbsc/src/osmo-bsc/Makefile.am
@@ -31,6 +31,7 @@ osmo_bsc_SOURCES = \
osmo_bsc_api.c \
osmo_bsc_grace.c \
osmo_bsc_msc.c \
+ osmo_bsc_reset.c \
osmo_bsc_sccp.c \
osmo_bsc_sigtran.c \
osmo_bsc_filter.c \
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
index 7d81a9e..739f93c 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
@@ -31,6 +31,7 @@
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/gsm0808_utils.h>
#include <openbsc/osmo_bsc_sigtran.h>
+#include <openbsc/osmo_bsc_reset.h>
#include <osmocom/core/byteswap.h>
#define IP_V4_ADDR_LEN 4
@@ -194,17 +195,10 @@ static int bssmap_handle_reset_ack(struct bsc_msc_data *msc,
struct msgb *msg, unsigned int length)
{
LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC No.: %i\n", msc->nr);
- msc->msc_con->reset_ack = true;
-#if 0
- struct msc_signal_data sig;
- struct bsc_msc_data *data;
-
- data = (struct bsc_msc_data *) msc;
- sig.data = data;
- osmo_signal_dispatch(SS_MSC, S_MSC_CONNECTED, &sig);
- osmo_signal_dispatch(SS_MSC, S_MSC_AUTHENTICATED, &sig);
-#endif
+ /* Inform the FSM that controls the RESET/RESET-ACK procedure
+ * that we have successfully received the reset-ack message */
+ reset_ack_confirm(msc);
return 0;
}
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_reset.c b/openbsc/src/osmo-bsc/osmo_bsc_reset.c
new file mode 100644
index 0000000..0baf080
--- /dev/null
+++ b/openbsc/src/osmo-bsc/osmo_bsc_reset.c
@@ -0,0 +1,190 @@
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * 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 <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/fsm.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <openbsc/debug.h>
+#include <openbsc/bsc_msc_data.h>
+#include <openbsc/osmo_bsc_sigtran.h>
+
+#define RESET_RESEND_INTERVAL 2 /* sec */
+#define RESET_RESEND_TIMER_NO 1234 /* FIXME: dig out the real timer number */
+#define BAD_CONNECTION_THRESOLD 3 /* connection failures */
+
+enum fsm_states {
+ ST_DISC, /* Disconnected from MSC */
+ ST_CONN, /* We have a confirmed connection to the MSC */
+};
+
+static const struct value_string fsm_state_names[] = {
+ {ST_DISC, "ST_DISC (disconnected)"},
+ {ST_CONN, "ST_CONN (connected)"},
+ {0, NULL},
+};
+
+enum fsm_evt {
+ EV_RESET_ACK, /* got reset acknowlegement from the MSC */
+ EV_N_DISCONNECT, /* lost a connection */
+ EV_N_CONNECT, /* made a successful connection */
+};
+
+static const struct value_string fsm_evt_names[] = {
+ {EV_RESET_ACK, "EV_RESET_ACK"},
+ {EV_N_DISCONNECT, "EV_N_DISCONNECT"},
+ {EV_N_CONNECT, "EV_N_CONNECT"},
+ {0, NULL},
+};
+
+/* Disconnected state */
+static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct bsc_msc_data *msc = (struct bsc_msc_data *)data;
+
+ LOGP(DMSC, LOGL_NOTICE, "fsm-state (msc-reset): %s, fsm-event: %s, MSC No.: %i\n",
+ get_value_string(fsm_state_names, ST_DISC), get_value_string(fsm_evt_names, event), msc->nr);
+ msc->msc_con->msc_conn_loss_count = 0;
+ osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0);
+}
+
+/* Connected state */
+static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct bsc_msc_data *msc = (struct bsc_msc_data *)data;
+
+ LOGP(DMSC, LOGL_NOTICE, "fsm-state (msc-reset): %s, fsm-event: %s, MSC No.: %i\n",
+ get_value_string(fsm_state_names, ST_CONN), get_value_string(fsm_evt_names, event), msc->nr);
+
+ OSMO_ASSERT(msc);
+
+ switch (event) {
+ case EV_N_DISCONNECT:
+ if (msc->msc_con->msc_conn_loss_count >= BAD_CONNECTION_THRESOLD) {
+ LOGP(DMSC, LOGL_NOTICE, "SIGTRAN connection to MSC No.: %i down, reconnecting...\n", msc->nr);
+ osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+ } else
+ msc->msc_con->msc_conn_loss_count++;
+ break;
+ case EV_N_CONNECT:
+ msc->msc_con->msc_conn_loss_count = 0;
+ break;
+ }
+}
+
+/* Timer callback to retransmit the reset signal */
+static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi)
+{
+ struct bsc_msc_data *msc = (struct bsc_msc_data *)fi->priv;
+
+ LOGP(DMSC, LOGL_NOTICE, "reset-ack timeout (T%i) in state %s, MSC No.: %i, resending...\n", fi->T,
+ get_value_string(fsm_state_names, fi->state), msc->nr);
+
+ osmo_bsc_sigtran_reset(msc);
+ osmo_bsc_sigtran_tx_reset(msc);
+
+ osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+ return 0;
+}
+
+static struct osmo_fsm_state fsm_states[] = {
+ [ST_DISC] = {
+ .in_event_mask = (1 << EV_RESET_ACK),
+ .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
+ .name = "DISC",
+ .action = fsm_disc_cb,
+ },
+ [ST_CONN] = {
+ .in_event_mask = (1 << EV_N_DISCONNECT) | (1 << EV_N_CONNECT),
+ .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
+ .name = "CONN",
+ .action = fsm_conn_cb,
+ },
+};
+
+/* State machine definition */
+static struct osmo_fsm fsm = {
+ .name = "FSM RESET",
+ .states = fsm_states,
+ .num_states = ARRAY_SIZE(fsm_states),
+ .log_subsys = DMSC,
+ .timer_cb = fsm_reset_ack_timeout_cb,
+};
+
+/* Create and start state machine which handles the reset/reset-ack procedure */
+void start_reset_fsm(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+
+ osmo_fsm_register(&fsm);
+ msc->msc_con->fsm_reset = osmo_fsm_inst_alloc(&fsm, NULL, NULL, LOGL_DEBUG, "FSM RESET INST");
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+
+ msc->msc_con->fsm_reset->priv = msc;
+
+ /* kick off reset-ack sending mechanism */
+ osmo_fsm_inst_state_chg(msc->msc_con->fsm_reset, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+}
+
+/* Confirm that we sucessfully received a reset acknowlege message */
+void reset_ack_confirm(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+
+ osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_RESET_ACK, msc);
+}
+
+/* Report a failed connection */
+void report_conn_fail(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+
+ osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_N_DISCONNECT, msc);
+}
+
+/* Report a successful connection */
+void report_conn_success(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+
+ osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_N_CONNECT, msc);
+}
+
+/* Check if we have a connection to a specified msc */
+bool sccp_conn_ready(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+ if (msc->msc_con->fsm_reset->state == ST_CONN)
+ return true;
+
+ return false;
+}
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_sigtran.c b/openbsc/src/osmo-bsc/osmo_bsc_sigtran.c
index bcd2946..3d3037b 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_sigtran.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_sigtran.c
@@ -1,4 +1,4 @@
-/* (C) 2017 by Sysmocom s.f.m.c. GmbH
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
@@ -31,6 +31,7 @@
#include <openbsc/osmo_bsc.h>
#include <openbsc/osmo_bsc_grace.h>
#include <openbsc/osmo_bsc_sigtran.h>
+#include <openbsc/osmo_bsc_reset.h>
/* A pointer to a list with all involved MSCs
* (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */
@@ -73,36 +74,14 @@ static int pick_free_conn_id(struct bsc_msc_data *msc)
return -1;
}
-/* Timer callback to handle the MSC reset procedure */
-static void msc_reset_timer_cb(void *data)
+/* Send reset to MSC */
+void osmo_bsc_sigtran_tx_reset(struct bsc_msc_data *msc)
{
- /* FIXME: Probably the reset procedure should be moved to osmo_bsc_bssap.c,
- * since it is clearly in the BSSAP's area of accountability */
- struct bsc_msc_data *msc = (struct bsc_msc_data *)data;
- struct msgb *msg = NULL;
-
- /* Stop sending RESET messages as soon as the
- * connection is marked as connected. */
- if (msc->msc_con->reset_ack)
- return;
-
+ struct msgb *msg;
LOGP(DMSC, LOGL_NOTICE, "Sending RESET to MSC No.: %i\n", msc->nr);
-
msg = gsm0808_create_reset();
osmo_sccp_tx_unitdata_msg(msc->msc_con->sccp_user, &msc->msc_con->g_calling_addr,
&msc->msc_con->g_called_addr, msg);
-
- osmo_timer_schedule(&msc->msc_con->msc_reset_timer, RESET_INTERVAL, 0);
-}
-
-/* Perform MSC reset procedure */
-static void msc_reset(struct bsc_msc_data *msc)
-{
- LOGP(DMSC, LOGL_NOTICE, "Starting RESET for MSC No.: %i\n", msc->nr);
- msc->msc_con->msc_reset_timer.cb = msc_reset_timer_cb;
- msc->msc_con->msc_reset_timer.data = msc;
- msc->msc_con->reset_ack = false;
- osmo_timer_schedule(&msc->msc_con->msc_reset_timer, RESET_INTERVAL, 0);
}
/* Find an MSC by its sigtran point code */
@@ -154,6 +133,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
{
struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;
struct osmo_sccp_user *scu = _scu;
+ struct osmo_bsc_sccp_con *bsc_con;
int rc = 0;
switch (OSMO_PRIM_HDR(&scu_prim->oph)) {
@@ -184,19 +164,34 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
/* Handle incoming connection oriented data */
DEBUGP(DMSC, "N-DATA.ind(%u, %s)\n", scu_prim->u.data.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+
+ /* Incoming data is a sign of a vital connection */
+ bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
+ if (bsc_con)
+ report_conn_success(bsc_con->msc);
+
rc = handle_data_from_msc(scu_prim->u.data.conn_id, oph->msg);
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
/* indication of disconnect */
if (msgb_l2len(oph->msg) > 0) {
- DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s)\n", scu_prim->u.disconnect.conn_id,
- osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+ DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id,
+ osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), scu_prim->u.disconnect.cause);
handle_data_from_msc(scu_prim->u.disconnect.conn_id, oph->msg);
} else
- DEBUGP(DRANAP, "N-DISCONNECT.ind(%u)\n", scu_prim->u.disconnect.conn_id);
+ DEBUGP(DRANAP, "N-DISCONNECT.ind(%u, cause=%i)\n", scu_prim->u.disconnect.conn_id,
+ scu_prim->u.disconnect.cause);
+
+ bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
+ if (bsc_con) {
+ /* We might have a connectivity problem. Maybe we need to go
+ * through the reset procedure again? */
+ if (scu_prim->u.disconnect.cause == 0)
+ report_conn_fail(bsc_con->msc);
- rc = osmo_bsc_sigtran_del_conn(get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id));
+ rc = osmo_bsc_sigtran_del_conn(bsc_con);
+ }
break;
default:
@@ -220,9 +215,8 @@ enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, s
LOGP(DMSC, LOGL_NOTICE, "Initalizing resources for new SIGTRAN connection to MSC No.: %i...\n", msc->nr);
- /* This should not trigger */
- if (!msc || !msc->msc_con->is_authenticated) {
- LOGP(DMSC, LOGL_ERROR, "How did this happen? MSC is not connected. Dropping.\n");
+ if (sccp_conn_ready(msc) == false) {
+ LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
return BSC_CON_REJECT_NO_LINK;
}
@@ -256,13 +250,22 @@ enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, s
/* Open a new connection oriented sigtran connection */
int osmo_bsc_sigtran_open_conn(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
{
- struct bsc_msc_data *msc = conn->msc;
- int conn_id = conn->conn_id;
+ struct bsc_msc_data *msc;
+ int conn_id;
int rc;
OSMO_ASSERT(conn);
OSMO_ASSERT(msg);
+ OSMO_ASSERT(conn->msc);
+
+ msc = conn->msc;
+
+ if (sccp_conn_ready(msc) == false) {
+ LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
+ return -EINVAL;
+ }
+ conn_id = conn->conn_id;
LOGP(DMSC, LOGL_NOTICE, "Opening new SIGTRAN connection (id=%i) to MSC No.: %i...\n", conn_id, msc->nr);
rc = osmo_sccp_tx_conn_req_msg(msc->msc_con->sccp_user, conn_id, &msc->msc_con->g_calling_addr,
@@ -280,11 +283,19 @@ int osmo_bsc_sigtran_send(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
OSMO_ASSERT(conn);
OSMO_ASSERT(msg);
+ OSMO_ASSERT(conn->msc);
msc = conn->msc;
+
+ if (sccp_conn_ready(msc) == false) {
+ LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
+ return -EINVAL;
+ }
+
conn_id = conn->conn_id;
LOGP(DMSC, LOGL_DEBUG, "Sending connection (id=%i) oriented data to MSC No.: %i...\n", conn_id, msc->nr);
+
rc = osmo_sccp_tx_data_msg(msc->msc_con->sccp_user, conn_id, msg);
return rc;
@@ -293,20 +304,44 @@ int osmo_bsc_sigtran_send(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
/* Delete a connection from the list with open connections
* (called by osmo_bsc_api.c on failing open connections and
* locally, when a connection is closed by the MSC */
-int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *sccp)
+int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *conn)
{
- if (!sccp)
+ if (!conn)
return 0;
- if (sccp->conn)
- LOGP(DMSC, LOGL_ERROR, "sccp connection not cleared -- forcefully clearing it now!\n");
+ if (conn->conn) {
+ LOGP(DMSC, LOGL_ERROR,
+ "sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n",
+ conn->conn_id);
+ bsc_subscr_con_free(conn->conn);
+ conn->conn = NULL;
- llist_del(&sccp->entry);
- talloc_free(sccp);
+ /* This bahaviour might be caused by a bad connection. Maybe we
+ * will have to go through the reset procedure again */
+ report_conn_fail(conn->msc);
+ }
+
+ llist_del(&conn->entry);
+ talloc_free(conn);
return 0;
}
+/* close all open connections */
+void osmo_bsc_sigtran_reset(struct bsc_msc_data *msc)
+{
+ struct osmo_bsc_sccp_con *conn;
+ struct osmo_bsc_sccp_con *conn_temp;
+
+ llist_for_each_entry_safe(conn, conn_temp, &active_connections, entry) {
+ if (conn->conn)
+ gsm0808_clear(conn->conn);
+ osmo_bsc_sigtran_del_conn(conn);
+ }
+
+ msc->msc_con->conn_id_counter = 0;
+}
+
/* Initalize osmo sigtran backhaul */
int osmo_bsc_sigtran_init(struct llist_head *mscs)
{
@@ -332,7 +367,7 @@ int osmo_bsc_sigtran_init(struct llist_head *mscs)
osmo_sccp_user_bind(msc->msc_con->sccp, msc_name, sccp_sap_up, SCCP_SSN_BSSAP);
/* Start MSC reset procedure */
- msc_reset(msc);
+ start_reset_fsm(msc);
}
return 0;