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 Change-Id: I876319b15103cc395e74597a52ce4d1a934915f4
This commit is contained in:
parent
813a230b55
commit
615db796d3
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
rc = osmo_bsc_sigtran_del_conn(get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id));
|
||||
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(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;
|
||||
|
|
Loading…
Reference in New Issue