Send RESET to MSC on start up

Automatically send RESET to the MSC as the BSCNAT starts up. Try it
again if it fails, in case the MSC was not started yet or if the SCCP
connection was not up yet (right now it does not seem possible to get
notified when the SCCP connection is up).

Related: SYS#5560
Related: https://osmocom.org/projects/osmo-bscnat/wiki/AoIP_OsmoBSCNAT#RESET
Change-Id: Icfec3ec0168c7040e88a536fa48da339349fb6cf
This commit is contained in:
Oliver Smith 2022-03-11 09:52:33 +01:00
parent 49e50de426
commit 70cd49dcae
7 changed files with 216 additions and 19 deletions

View File

@ -23,3 +23,5 @@
int bssap_handle_udt(struct bsc_nat_sccp_inst *sccp_inst, struct osmo_sccp_addr *addr, struct msgb *msgb,
unsigned int length);
int bssap_tx_reset(struct bsc_nat_sccp_inst *sccp_inst, struct osmo_sccp_addr *addr);

View File

@ -19,11 +19,13 @@
#pragma once
#include <osmocom/core/fsm.h>
#include <osmocom/sigtran/sccp_sap.h>
struct msc {
struct llist_head list;
struct osmo_sccp_addr addr;
struct osmo_fsm_inst *fi;
};
struct msc *msc_alloc(struct osmo_sccp_addr *addr);
@ -31,4 +33,7 @@ int msc_alloc_from_addr_book(void);
struct msc *msc_get(void);
void msc_tx_reset(struct msc *msc);
void msc_rx_reset_ack(struct msc *msc);
void msc_free(struct msc *msc);

View File

@ -32,6 +32,7 @@ osmo_bsc_nat_SOURCES = \
logging.c \
main.c \
msc.c \
msc_fsm.c \
vty.c \
$(NULL)

View File

@ -286,24 +286,6 @@ static int sccp_sap_up_ran(struct osmo_prim_hdr *oph, void *scu)
case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
/* connection-less data received */
rc = bssap_handle_udt(sccp_inst, &prim->u.unitdata.calling_addr, oph->msg, msgb_l2len(oph->msg));
/* FIXME: don't forward this to the MSC anymore, as soon as the
* BSCNAT is able to do the RESET to MSC by itself. */
addr = &prim->u.unitdata.calling_addr;
if (sccp_sap_get_peer_addr_out(sccp_inst, addr, &peer_addr_out) < 0)
goto error;
LOGP(DMAIN, LOGL_DEBUG, "Fwd to %s\n", bsc_nat_print_addr_cn(&peer_addr_out));
/* oph->msg stores oph and unitdata msg. Move oph->msg->data to
* unitdata msg and send it again. */
msgb_pull_to_l2(oph->msg);
osmo_sccp_tx_unitdata(g_bsc_nat->cn.sccp_inst->scu,
&g_bsc_nat->cn.sccp_inst->addr,
&peer_addr_out,
oph->msg->data,
msgb_length(oph->msg));
break;
default:

View File

@ -25,6 +25,50 @@
#include <osmocom/bsc_nat/bsc.h>
#include <osmocom/bsc_nat/bsc_nat.h>
#include <osmocom/bsc_nat/logging.h>
#include <osmocom/bsc_nat/msc.h>
int bssap_tx_reset(struct bsc_nat_sccp_inst *sccp_inst, struct osmo_sccp_addr *addr)
{
enum bsc_nat_net net = sccp_inst == g_bsc_nat->cn.sccp_inst ? BSC_NAT_NET_CN : BSC_NAT_NET_RAN;
LOGP(DMAIN, LOGL_NOTICE, "Tx RESET to %s\n", bsc_nat_print_addr(net, addr));
struct msgb *msg = gsm0808_create_reset();
return osmo_sccp_tx_unitdata_msg(sccp_inst->scu, &sccp_inst->addr, addr, msg);
}
static int bssap_cn_handle_reset_ack(struct osmo_sccp_addr *addr, struct msgb *msg, unsigned int length)
{
struct msc *msc = msc_get();
if (msc->addr.pc != addr->pc) {
LOGP(DMAIN, LOGL_ERROR, "Unexpected Rx RESET ACK in CN from %s, which is not %s\n",
osmo_ss7_pointcode_print(NULL, addr->pc), talloc_get_name(msc));
return -1;
}
LOGP(DMAIN, LOGL_NOTICE, "Rx RESET ACK from %s\n", talloc_get_name(msc));
msc_rx_reset_ack(msc);
return 0;
}
static int bssap_cn_rcvmsg_udt(struct osmo_sccp_addr *addr, struct msgb *msg, unsigned int length)
{
int ret = 0;
switch (msg->l3h[0]) {
case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
ret = bssap_cn_handle_reset_ack(addr, msg, length);
break;
default:
LOGP(DMAIN, LOGL_NOTICE, "Unimplemented BSSMAP UDT %s\n", gsm0808_bssap_name(msg->l3h[0]));
break;
}
return ret;
}
static int bssap_ran_handle_reset(struct osmo_sccp_addr *addr, struct msgb *msg, unsigned int length)
{
@ -69,7 +113,8 @@ static int bssap_rcvmsg_udt(struct bsc_nat_sccp_inst *sccp_inst, struct osmo_scc
LOGP(DMAIN, LOGL_NOTICE, "Rx UDT BSSMAP %s\n", gsm0808_bssap_name(msg->l3h[0]));
/* NOTE: bssap_cn_rcvmsg_udt() will be added in a future patch */
if (sccp_inst == g_bsc_nat->cn.sccp_inst)
return bssap_cn_rcvmsg_udt(addr, msg, length);
return bssap_ran_rcvmsg_udt(addr, msg, length);
}

View File

@ -23,6 +23,8 @@
#include <osmocom/bsc_nat/bsc_nat.h>
#include <osmocom/bsc_nat/logging.h>
extern struct osmo_fsm msc_fsm;
struct msc *msc_alloc(struct osmo_sccp_addr *addr)
{
struct msc *msc = talloc_zero(g_bsc_nat, struct msc);
@ -37,6 +39,11 @@ struct msc *msc_alloc(struct osmo_sccp_addr *addr)
INIT_LLIST_HEAD(&msc->list);
llist_add(&msc->list, &g_bsc_nat->cn.mscs);
msc->fi = osmo_fsm_inst_alloc(&msc_fsm, msc, msc, LOGL_INFO, NULL);
OSMO_ASSERT(msc->fi);
msc_tx_reset(msc);
return msc;
}
@ -67,5 +74,6 @@ void msc_free(struct msc *msc)
{
LOGP(DMAIN, LOGL_DEBUG, "Del %s\n", talloc_get_name(msc));
llist_del(&msc->list);
osmo_fsm_inst_free(msc->fi);
talloc_free(msc);
}

154
src/osmo-bsc-nat/msc_fsm.c Normal file
View File

@ -0,0 +1,154 @@
/* (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Oliver Smith <osmith@sysmocom.de>
* All Rights Reserved
*
* 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/lienses/>.
*
*/
#include "config.h"
#include <osmocom/core/fsm.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/bsc_nat/bsc_nat.h>
#include <osmocom/bsc_nat/bssap.h>
#include <osmocom/bsc_nat/logging.h>
#include <osmocom/bsc_nat/msc.h>
#define X(s) (1 << (s))
enum msc_fsm_states {
MSC_FSM_ST_DISCONNECTED,
MSC_FSM_ST_CONNECTING,
MSC_FSM_ST_CONNECTED,
};
enum msc_fsm_events {
MSC_FSM_EV_TX_RESET,
MSC_FSM_EV_RX_RESET_ACK,
MSC_FSM_EV_DISCONNECT
};
static void st_connecting(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case MSC_FSM_EV_RX_RESET_ACK:
osmo_fsm_inst_state_chg(fi, MSC_FSM_ST_CONNECTED, 0, 0);
break;
default:
OSMO_ASSERT(false);
}
}
static void st_disconnected_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_stat)
{
osmo_fsm_inst_dispatch(fi, MSC_FSM_EV_TX_RESET, NULL);
}
static void st_disconnected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct msc *msc = fi->priv;
switch (event) {
case MSC_FSM_EV_TX_RESET:
LOGP(DMAIN, LOGL_DEBUG, "Tx RESET to %s\n", talloc_get_name(msc));
if (bssap_tx_reset(g_bsc_nat->cn.sccp_inst, &msc->addr) < 0) {
LOGP(DMAIN, LOGL_ERROR, "Could not send RESET to MSC (SCCP not up yet?)\n");
}
/* Retry in 3s if RESET ACK was not received from MSC */
osmo_fsm_inst_state_chg(fi, MSC_FSM_ST_CONNECTING, 3, 0);
break;
default:
OSMO_ASSERT(false);
}
}
int msc_fsm_timer_cb(struct osmo_fsm_inst *fi)
{
switch (fi->state) {
case MSC_FSM_ST_CONNECTING:
osmo_fsm_inst_state_chg(fi, MSC_FSM_ST_DISCONNECTED, 0, 0);
break;
default:
OSMO_ASSERT(false);
}
return 0;
}
static struct osmo_fsm_state msc_fsm_states[] = {
[MSC_FSM_ST_DISCONNECTED] = {
.name = "DISCONNECTED",
.in_event_mask = 0
| X(MSC_FSM_EV_TX_RESET)
,
.out_state_mask = 0
| X(MSC_FSM_ST_CONNECTING)
,
.action = st_disconnected,
.onenter = st_disconnected_on_enter,
},
[MSC_FSM_ST_CONNECTING] = {
.name = "CONNECTING",
.in_event_mask = 0
| X(MSC_FSM_EV_RX_RESET_ACK)
,
.out_state_mask = 0
| X(MSC_FSM_ST_CONNECTED)
| X(MSC_FSM_ST_DISCONNECTED)
,
.action = st_connecting,
},
[MSC_FSM_ST_CONNECTED] = {
.name = "CONNECTED",
.in_event_mask = 0
| X(MSC_FSM_EV_DISCONNECT)
,
.out_state_mask = 0
| X(MSC_FSM_ST_DISCONNECTED)
,
},
};
const struct value_string msc_fsm_event_names[] = {
OSMO_VALUE_STRING(MSC_FSM_EV_TX_RESET),
OSMO_VALUE_STRING(MSC_FSM_EV_RX_RESET_ACK),
OSMO_VALUE_STRING(MSC_FSM_EV_DISCONNECT),
{ 0, NULL }
};
struct osmo_fsm msc_fsm = {
.name = "MSC",
.states = msc_fsm_states,
.num_states = ARRAY_SIZE(msc_fsm_states),
.log_subsys = DMAIN,
.event_names = msc_fsm_event_names,
.timer_cb = msc_fsm_timer_cb,
};
static __attribute__((constructor)) void msc_fsm_init(void)
{
OSMO_ASSERT(osmo_fsm_register(&msc_fsm) == 0);
}
void msc_tx_reset(struct msc *msc)
{
osmo_fsm_inst_dispatch(msc->fi, MSC_FSM_EV_TX_RESET, NULL);
}
void msc_rx_reset_ack(struct msc *msc)
{
osmo_fsm_inst_dispatch(msc->fi, MSC_FSM_EV_RX_RESET_ACK, NULL);
}