From 8b0d8a97fb5cddb718c0b35af02bbcfe4599bdc5 Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Tue, 6 Jun 2017 14:31:36 +0200 Subject: 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 --- openbsc/include/openbsc/Makefile.am | 1 + openbsc/include/openbsc/bsc_msc.h | 4 +- openbsc/include/openbsc/bsc_msc_data.h | 1 + openbsc/include/openbsc/osmo_bsc_reset.h | 34 ++++++ openbsc/include/openbsc/osmo_bsc_sigtran.h | 8 ++ openbsc/src/libmsc/a_iface.c | 28 +++++ openbsc/src/libmsc/a_iface_bssap.c | 3 +- openbsc/src/osmo-bsc/Makefile.am | 1 + openbsc/src/osmo-bsc/osmo_bsc_bssap.c | 14 +-- openbsc/src/osmo-bsc/osmo_bsc_reset.c | 190 +++++++++++++++++++++++++++++ openbsc/src/osmo-bsc/osmo_bsc_sigtran.c | 119 +++++++++++------- 11 files changed, 349 insertions(+), 54 deletions(-) create mode 100644 openbsc/include/openbsc/osmo_bsc_reset.h create mode 100644 openbsc/src/osmo-bsc/osmo_bsc_reset.c (limited to 'openbsc') diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index be7595877..e1ae6d2d8 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 8b9553bfa..1b1c2d8f4 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 a819abab3..0d7ec224d 100644 --- a/openbsc/include/openbsc/bsc_msc_data.h +++ b/openbsc/include/openbsc/bsc_msc_data.h @@ -38,6 +38,7 @@ #include #include #include +#include #include diff --git a/openbsc/include/openbsc/osmo_bsc_reset.h b/openbsc/include/openbsc/osmo_bsc_reset.h new file mode 100644 index 000000000..578f763e6 --- /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 . + * + */ + +/* 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 37085b653..c57783dc8 100644 --- a/openbsc/include/openbsc/osmo_bsc_sigtran.h +++ b/openbsc/include/openbsc/osmo_bsc_sigtran.h @@ -20,6 +20,8 @@ #pragma once +#include + /* 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 9ff1b48f8..ffde21d85 100644 --- a/openbsc/src/libmsc/a_iface.c +++ b/openbsc/src/libmsc/a_iface.c @@ -36,6 +36,7 @@ #include #include #include +#include #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 eafc4e418..9a0706d8a 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 d0d0e3afc..32e2cee72 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 7d81a9ece..739f93c05 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #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 000000000..0baf08089 --- /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 . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 bcd294620..3d3037b80 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 #include #include +#include /* 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; -- cgit v1.2.3