WIP: Integrate AoIP into OsmoBSC

Change-Id: I5ae4e05ee7c57cad341ea5e86af37c1f6b0ffa77
This commit is contained in:
Philipp Maier
2017-04-12 15:26:04 +02:00
committed by Neels Hofmeyr
parent 1168969378
commit 2932bc4955
15 changed files with 519 additions and 39 deletions

View File

@@ -58,6 +58,7 @@ AC_ARG_ENABLE([osmo-bsc], [AS_HELP_STRING([--enable-osmo-bsc], [Build the Osmo B
[osmo_ac_build_bsc="$enableval"],[osmo_ac_build_bsc="no"])
if test "$osmo_ac_build_bsc" = "yes" ; then
PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.6)
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran) # TODO version?
fi
AM_CONDITIONAL(BUILD_BSC, test "x$osmo_ac_build_bsc" = "xyes")
AC_SUBST(osmo_ac_build_bsc)

View File

@@ -67,6 +67,7 @@ noinst_HEADERS = \
osmo_bsc_grace.h \
osmo_bsc_rf.h \
osmo_msc.h \
osmo_bsc_sigtran.h \
bsc_msc_data.h \
osmux.h \
paging.h \

View File

@@ -24,6 +24,7 @@
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <netinet/in.h>
@@ -37,6 +38,7 @@ struct bsc_msc_dest {
struct bsc_msc_connection {
/* FIXME: Remove stuff that is no longer needed! */
struct osmo_wqueue write_queue;
int is_connected;
int is_authenticated;
@@ -52,6 +54,15 @@ struct bsc_msc_connection {
struct osmo_timer_list timeout_timer;
struct msgb *pending_msg;
/* Sigtran connection data */
struct osmo_sccp_instance *sccp;
struct osmo_sccp_user *sccp_user;
struct osmo_sccp_addr g_calling_addr;
struct osmo_sccp_addr g_called_addr;
struct osmo_timer_list msc_reset_timer;
bool reset_ack;
int conn_id_counter;
};
struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dest);

View File

@@ -32,6 +32,13 @@
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/sccp_helpers.h>
#include <osmocom/sigtran/protocol/sua.h>
#include <osmocom/sigtran/protocol/m3ua.h>
#include <regex.h>
struct osmo_bsc_rf;

View File

@@ -40,6 +40,7 @@ enum {
DPCU,
DVLR,
DIUCS,
DSIGTRAN,
Debug_LastEntry,
};

View File

@@ -44,6 +44,9 @@ struct osmo_bsc_sccp_con {
uint8_t new_subscriber;
struct bsc_filter_state filter_state;
/* Sigtran connection ID */
int conn_id;
};
struct bsc_api *osmo_bsc_api();

View File

@@ -0,0 +1,39 @@
/* (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/>.
*
*/
#pragma once
/* 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);
/* Open a new connection oriented sigtran connection */
int osmo_bsc_sigtran_open_conn(struct osmo_bsc_sccp_con *conn, struct msgb *msg);
/* Send data to MSC */
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);
/* Initalize osmo sigtran backhaul */
int osmo_bsc_sigtran_init(struct llist_head *mscs);

View File

@@ -189,6 +189,12 @@ static const struct log_info_cat default_categories[] = {
.description = "Iu-CS Protocol",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DSIGTRAN] = {
.name = "DSIGTRAN",
.description = "SIGTRAN Signalling Transport",
.color = "\033[1;29m",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
};
static int filter_fn(const struct log_context *ctx, struct log_target *tar)

View File

@@ -14,6 +14,7 @@ AM_CFLAGS = \
$(LIBOSMOSCCP_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(LIBOSMOSIGTRAN_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
@@ -31,6 +32,7 @@ osmo_bsc_SOURCES = \
osmo_bsc_grace.c \
osmo_bsc_msc.c \
osmo_bsc_sccp.c \
osmo_bsc_sigtran.c \
osmo_bsc_filter.c \
osmo_bsc_bssap.c \
osmo_bsc_audio.c \
@@ -52,4 +54,5 @@ osmo_bsc_LDADD = \
$(LIBOSMOCTRL_LIBS) \
$(COVERAGE_LDFLAGS) \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
$(NULL)

View File

@@ -27,6 +27,7 @@
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/sccp/sccp.h>
#include <openbsc/osmo_bsc_sigtran.h>
#define return_when_not_connected(conn) \
if (!conn->sccp_con) {\
@@ -45,7 +46,7 @@
LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n"); \
return; \
} \
bsc_queue_for_msc(conn->sccp_con, resp);
osmo_bsc_sigtran_send(conn->sccp_con, resp);
static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
static int complete_layer3(struct gsm_subscriber_connection *conn,
@@ -263,7 +264,8 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
}
/* allocate resource for a new connection */
ret = bsc_create_new_connection(conn, msc, send_ping);
//ret = bsc_create_new_connection(conn, msc, send_ping);
ret = osmo_bsc_sigtran_new_conn(conn, msc);
if (ret != BSC_CON_SUCCESS) {
/* allocation has failed */
@@ -292,13 +294,13 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
if (!resp) {
LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n");
sccp_connection_free(conn->sccp_con->sccp);
bsc_delete_connection(conn->sccp_con);
osmo_bsc_sigtran_del_conn(conn->sccp_con);
return BSC_API_CONN_POL_REJECT;
}
if (bsc_open_connection(conn->sccp_con, resp) != 0) {
if (osmo_bsc_sigtran_open_conn(conn->sccp_con, resp) != 0) {
sccp_connection_free(conn->sccp_con->sccp);
bsc_delete_connection(conn->sccp_con);
osmo_bsc_sigtran_del_conn(conn->sccp_con);
msgb_free(resp);
return BSC_API_CONN_POL_REJECT;
}
@@ -474,7 +476,7 @@ static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t ca
return 1;
}
bsc_queue_for_msc(sccp, resp);
osmo_bsc_sigtran_send(sccp, resp);
return 1;
}

View File

@@ -29,6 +29,7 @@
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm0808.h>
#include <openbsc/osmo_bsc_sigtran.h>
/*
* helpers for the assignment command
@@ -92,7 +93,19 @@ enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
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\n");
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
return 0;
}
@@ -199,7 +212,7 @@ static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
return -1;
}
bsc_queue_for_msc(conn, resp);
osmo_bsc_sigtran_send(conn, resp);
return 0;
}
@@ -276,7 +289,7 @@ reject:
return -1;
}
bsc_queue_for_msc(conn, resp);
osmo_bsc_sigtran_send(conn, resp);
return -1;
}
@@ -383,7 +396,7 @@ reject:
return -1;
}
bsc_queue_for_msc(conn, resp);
osmo_bsc_sigtran_send(conn, resp);
return -1;
}

View File

@@ -28,6 +28,7 @@
#include <openbsc/vty.h>
#include <openbsc/ipaccess.h>
#include <openbsc/ctrl.h>
#include <openbsc/osmo_bsc_sigtran.h>
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/ctrl/control_if.h>
@@ -269,8 +270,25 @@ int main(int argc, char **argv)
}
if (osmo_bsc_sccp_init(bsc_gsmnet) != 0) {
LOGP(DNM, LOGL_ERROR, "Failed to register SCCP.\n");
llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry) {
/* FIXME: This has to come from a config file */
msc->msc_con->g_calling_addr.presence = OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC;
msc->msc_con->g_calling_addr.ssn = SCCP_SSN_BSSAP;
msc->msc_con->g_calling_addr.ri = OSMO_SCCP_RI_SSN_PC;
msc->msc_con->g_calling_addr.pc = 23;
msc->msc_con->g_called_addr.presence = OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC;
msc->msc_con->g_called_addr.ssn = SCCP_SSN_BSSAP;
msc->msc_con->g_called_addr.ri = OSMO_SCCP_RI_SSN_PC;
msc->msc_con->g_called_addr.pc = 1;
}
// if (osmo_bsc_sccp_init(bsc_gsmnet) != 0) {
// LOGP(DNM, LOGL_ERROR, "Failed to register SCCP.\n");
// exit(1);
// }
if (osmo_bsc_sigtran_init(&bsc_gsmnet->bsc_data->mscs) != 0) {
LOGP(DNM, LOGL_ERROR, "Failed to initalize sigtran backhaul.\n");
exit(1);
}

View File

@@ -42,7 +42,7 @@
#include <netinet/tcp.h>
#include <unistd.h>
#if 0
static void initialize_if_needed(struct bsc_msc_connection *conn);
static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn);
static void send_id_get_response(struct bsc_msc_data *data, int fd, struct msgb *inp);
@@ -52,6 +52,8 @@ static void schedule_ping_pong(struct bsc_msc_data *data);
/*
* MGCP forwarding code
*/
#endif
static int mgcp_do_read(struct osmo_fd *fd)
{
struct bsc_msc_data *data = (struct bsc_msc_data *) fd->data;
@@ -93,6 +95,7 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
return ret;
}
#if 0
static void mgcp_forward(struct bsc_msc_data *data, struct msgb *msg)
{
struct msgb *mgcp;
@@ -115,6 +118,7 @@ static void mgcp_forward(struct bsc_msc_data *data, struct msgb *msg)
msgb_free(mgcp);
}
}
#endif
static int mgcp_create_port(struct bsc_msc_data *data)
{
@@ -168,6 +172,7 @@ static int mgcp_create_port(struct bsc_msc_data *data)
return 0;
}
/*
* Send data to the network
*/
@@ -183,6 +188,7 @@ int msc_queue_write(struct bsc_msc_connection *conn, struct msgb *msg, int proto
return 0;
}
#if 0
int msc_queue_write_with_ping(struct bsc_msc_connection *conn,
struct msgb *msg, int proto)
{
@@ -356,10 +362,10 @@ static void msc_ping_timeout_cb(void *_data)
static void msc_pong_timeout_cb(void *_data)
{
struct bsc_msc_data *data = (struct bsc_msc_data *) _data;
// struct bsc_msc_data *data = (struct bsc_msc_data *) _data;
LOGP(DMSC, LOGL_ERROR, "MSC didn't answer PING. Closing connection.\n");
bsc_msc_lost(data->msc_con);
// bsc_msc_lost(data->msc_con);
}
static void msc_connection_connected(struct bsc_msc_connection *con)
@@ -368,12 +374,12 @@ static void msc_connection_connected(struct bsc_msc_connection *con)
struct bsc_msc_data *data;
int ret, on;
on = 1;
ret = setsockopt(con->write_queue.bfd.fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
if (ret != 0)
LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
// ret = setsockopt(con->write_queue.bfd.fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
// if (ret != 0)
// LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
data = (struct bsc_msc_data *) con->write_queue.bfd.data;
msc_ping_timeout_cb(data);
// data = (struct bsc_msc_data *) con->write_queue.bfd.data;
// msc_ping_timeout_cb(data);
sig.data = data;
osmo_signal_dispatch(SS_MSC, S_MSC_CONNECTED, &sig);
@@ -385,20 +391,20 @@ static void msc_connection_connected(struct bsc_msc_connection *con)
*/
static void msc_connection_was_lost(struct bsc_msc_connection *msc)
{
struct msc_signal_data sig;
struct bsc_msc_data *data;
// struct msc_signal_data sig;
// struct bsc_msc_data *data;
LOGP(DMSC, LOGL_ERROR, "Lost MSC connection. Freing stuff.\n");
data = (struct bsc_msc_data *) msc->write_queue.bfd.data;
osmo_timer_del(&data->ping_timer);
osmo_timer_del(&data->pong_timer);
sig.data = data;
osmo_signal_dispatch(SS_MSC, S_MSC_LOST, &sig);
// data = (struct bsc_msc_data *) msc->write_queue.bfd.data;
// osmo_timer_del(&data->ping_timer);
// osmo_timer_del(&data->pong_timer);
//
// sig.data = data;
// osmo_signal_dispatch(SS_MSC, S_MSC_LOST, &sig);
msc->is_authenticated = 0;
bsc_msc_schedule_connect(msc);
// bsc_msc_schedule_connect(msc);
}
static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn)
@@ -515,6 +521,8 @@ static void send_id_get_response(struct bsc_msc_data *data, int fd, struct msgb
osmo_signal_dispatch(SS_MSC, S_MSC_AUTHENTICATED, &sig);
}
#endif
int osmo_bsc_msc_init(struct bsc_msc_data *data)
{
if (mgcp_create_port(data) != 0)
@@ -526,19 +534,24 @@ int osmo_bsc_msc_init(struct bsc_msc_data *data)
return -1;
}
osmo_timer_setup(&data->ping_timer, msc_ping_timeout_cb, data);
osmo_timer_setup(&data->pong_timer, msc_pong_timeout_cb, data);
// osmo_timer_setup(&data->ping_timer, msc_ping_timeout_cb, data);
// osmo_timer_setup(&data->pong_timer, msc_pong_timeout_cb, data);
data->msc_con->write_queue.bfd.data = data;
data->msc_con->connection_loss = msc_connection_was_lost;
data->msc_con->connected = msc_connection_connected;
data->msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
data->msc_con->write_queue.write_cb = msc_alink_do_write;
bsc_msc_connect(data->msc_con);
// data->msc_con->connection_loss = msc_connection_was_lost;
// data->msc_con->connected = msc_connection_connected;
// data->msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
// data->msc_con->write_queue.write_cb = msc_alink_do_write;
// bsc_msc_connect(data->msc_con);
data->msc_con->is_connected = 1;
data->msc_con->is_authenticated = 1;
return 0;
}
struct bsc_msc_data *osmo_msc_data_find(struct gsm_network *net, int nr)
{
struct bsc_msc_data *msc_data;
@@ -584,3 +597,4 @@ struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr)
return msc_data;
}

View File

@@ -37,6 +37,7 @@
/* SCCP helper */
#define SCCP_IT_TIMER 60
#if 0
static LLIST_HEAD(active_connections);
static void free_queued(struct osmo_bsc_sccp_con *conn)
@@ -172,6 +173,9 @@ static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
{
printf("==================> bsc_queue_for_msc()\n");
#if 0
struct sccp_connection *sccp = conn->sccp;
if (sccp->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
@@ -189,6 +193,7 @@ int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
conn->sccp_queue_size += 1;
msgb_enqueue(&conn->sccp_queue, msg);
}
#endif
return 0;
}
@@ -196,6 +201,9 @@ int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct bsc_msc_data *msc, int send_ping)
{
printf("==================> bsc_con bsc_create_new_connection()\n");
#if 0
struct osmo_bsc_sccp_con *bsc_con;
struct sccp_connection *sccp;
@@ -243,18 +251,29 @@ enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
llist_add_tail(&bsc_con->entry, &active_connections);
conn->sccp_con = bsc_con;
return BSC_CON_SUCCESS;
#endif
return BSC_CON_SUCCESS;
}
int bsc_open_connection(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
{
osmo_timer_schedule(&conn->sccp_cc_timeout, 10, 0);
sccp_connection_connect(conn->sccp, &sccp_ssn_bssap, msg);
msgb_free(msg);
printf("======================> bsc_open_connection()\n");
// osmo_timer_schedule(&conn->sccp_cc_timeout, 10, 0);
// sccp_connection_connect(conn->sccp, &sccp_ssn_bssap, msg);
// msgb_free(msg);
return 0;
}
int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp)
{
printf("======================> bsc_delete_connection()\n");
return 0;
#if 0
if (!sccp)
return 0;
@@ -266,6 +285,7 @@ int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp)
osmo_timer_del(&sccp->sccp_cc_timeout);
talloc_free(sccp);
return 0;
#endif
}
static void bsc_notify_msc_lost(struct osmo_bsc_sccp_con *con)
@@ -326,3 +346,4 @@ int osmo_bsc_sccp_init(struct gsm_network *gsmnet)
return 0;
}
#endif

View File

@@ -0,0 +1,340 @@
/* (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/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sccp/sccp_types.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/core/msgb.h>
#include <openbsc/bsc_msc_data.h>
#include <openbsc/debug.h>
#include <openbsc/osmo_bsc.h>
#include <openbsc/osmo_bsc_grace.h>
#include <openbsc/osmo_bsc_sigtran.h>
/* A pointer to a list with all involved MSCs
* (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */
static struct llist_head *msc_list;
#define RESET_INTERVAL 1 /* sek */
#define SCCP_MSG_MAXSIZE 1024
static LLIST_HEAD(active_connections);
/* Helper function to Check if the given connection id is already assigned */
static struct osmo_bsc_sccp_con *get_bsc_conn_by_conn_id(int conn_id)
{
conn_id &= 0xFFFFFF;
struct osmo_bsc_sccp_con *bsc_con;
llist_for_each_entry(bsc_con, &active_connections, entry) {
if (bsc_con->conn_id == conn_id)
return bsc_con;
}
return NULL;
}
/* Pick a free connection id */
static int pick_free_conn_id(struct bsc_msc_data *msc)
{
int conn_id = msc->msc_con->conn_id_counter;
int i;
for (i = 0; i < 0xFFFFFF; i++) {
conn_id++;
conn_id &= 0xFFFFFF;
if (get_bsc_conn_by_conn_id(conn_id) == false) {
msc->msc_con->conn_id_counter = conn_id;
return conn_id;
}
}
return -1;
}
/* Timer callback to handle the MSC reset procedure */
static void msc_reset_timer_cb(void *data)
{
/* 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;
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 */
static struct bsc_msc_data *get_msc_by_addr(struct osmo_sccp_addr *calling_addr)
{
struct bsc_msc_data *msc;
llist_for_each_entry(msc, msc_list, entry) {
if (memcmp(calling_addr, &msc->msc_con->g_called_addr, sizeof(*calling_addr)) == 0)
return msc;
}
LOGP(DMSC, LOGL_ERROR, "Unable to find MSC data under address: %s\n", osmo_sccp_addr_dump(calling_addr));
return NULL;
}
/* Send data to MSC, use the connection id which MSC it is */
static int handle_data_from_msc(int conn_id, struct msgb *msg)
{
struct osmo_bsc_sccp_con *bsc_con = get_bsc_conn_by_conn_id(conn_id);
int rc = -EINVAL;
if (bsc_con) {
msg->l3h = msgb_l2(msg);
rc = bsc_handle_dt1(bsc_con, msg, msgb_l2len(msg));
} else
LOGP(DMSC, LOGL_NOTICE, "incoming data from unknown connection id: %i\n", conn_id);
return rc;
}
/* Sent unitdata to MSC, use the point code to determine which MSC it is */
static int handle_unitdata_from_msc(struct osmo_sccp_addr *calling_addr, struct msgb *msg)
{
struct bsc_msc_data *msc = get_msc_by_addr(calling_addr);
int rc = -EINVAL;
if (msc) {
msg->l3h = msgb_l2(msg);
rc = bsc_handle_udt(msc, msg, msgb_l2len(msg));
} else
LOGP(DMSC, LOGL_NOTICE, "incoming unitdata data from unknown remote address: %s\n",
osmo_sccp_addr_dump(calling_addr));
return rc;
}
/* Callback function, called by the SSCP stack when data arrives */
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;
int rc = 0;
switch (OSMO_PRIM_HDR(&scu_prim->oph)) {
case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
/* Handle inbound UNITDATA */
DEBUGP(DMSC, "N-UNITDATA.ind(%s)\n", osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
rc = handle_unitdata_from_msc(&scu_prim->u.unitdata.calling_addr, oph->msg);
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):
/* Handle (Reject) inbound connections */
DEBUGP(DMSC, "N-CONNECT.ind(X->%u)\n", scu_prim->u.connect.conn_id);
LOGP(DMSC, LOGL_DEBUG, "Rejecting inbound SCCP connection...\n");
rc = osmo_sccp_tx_disconn(scu, scu_prim->u.connect.conn_id, &scu_prim->u.connect.called_addr, 0);
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
/* Handle outbound connection confirmation */
if (msgb_l2len(oph->msg) > 0) {
DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
rc = handle_data_from_msc(scu_prim->u.connect.conn_id, oph->msg);
} else
DEBUGP(DRANAP, "N-CONNECT.cnf(%u)\n", scu_prim->u.connect.conn_id);
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
/* 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)));
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)));
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);
rc = osmo_bsc_sigtran_del_conn(get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id));
break;
default:
LOGP(DMSC, LOGL_ERROR, "Unhandled SIGTRAN primitive: %u:%u\n", oph->primitive, oph->operation);
break;
}
msgb_free(oph->msg);
return rc;
}
/* 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)
{
struct osmo_bsc_sccp_con *bsc_con;
int conn_id;
OSMO_ASSERT(conn);
OSMO_ASSERT(msc);
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");
return BSC_CON_REJECT_NO_LINK;
}
if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) {
LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
return BSC_CON_REJECT_RF_GRACE;
}
bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
if (!bsc_con) {
LOGP(DMSC, LOGL_ERROR, "Failed to allocate new SIGTRAN connection.\n");
return BSC_CON_NO_MEM;
}
bsc_con->msc = msc;
bsc_con->conn = conn;
llist_add_tail(&bsc_con->entry, &active_connections);
conn->sccp_con = bsc_con;
/* Pick a free connection id */
conn_id = pick_free_conn_id(msc);
if (conn_id < 0)
return BSC_CON_REJECT_NO_LINK;
bsc_con->conn_id = conn_id;
LOGP(DMSC, LOGL_NOTICE, "Allocated new connection id: %i\n", conn_id);
return BSC_CON_SUCCESS;
}
/* 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;
int rc;
OSMO_ASSERT(conn);
OSMO_ASSERT(msg);
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,
&msc->msc_con->g_called_addr, msg);
return rc;
}
/* Send data to MSC */
int osmo_bsc_sigtran_send(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
{
int conn_id;
int rc;
struct bsc_msc_data *msc;
OSMO_ASSERT(conn);
OSMO_ASSERT(msg);
msc = conn->msc;
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;
}
/* 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)
{
if (!sccp)
return 0;
if (sccp->conn)
LOGP(DMSC, LOGL_ERROR, "sccp connection not cleared -- forcefully clearing it now!\n");
llist_del(&sccp->entry);
talloc_free(sccp);
return 0;
}
/* Initalize osmo sigtran backhaul */
int osmo_bsc_sigtran_init(struct llist_head *mscs)
{
/* FIXME: Remove hardcoded IP-Addresses */
/* FIXME: Use STP! */
struct bsc_msc_data *msc;
char msc_name[256];
OSMO_ASSERT(mscs);
osmo_ss7_init();
msc_list = mscs;
llist_for_each_entry(msc, msc_list, entry) {
snprintf(msc_name, sizeof(msc_name), "MSC No.: %u", msc->nr);
LOGP(DMSC, LOGL_NOTICE, "Initalizing SCCP connection to %s\n", msc_name);
/* SCCP Protocol stack */
msc->msc_con->sccp =
osmo_sccp_simple_client(NULL, msc_name, msc->msc_con->g_calling_addr.pc,
OSMO_SS7_ASP_PROT_M3UA, 0, NULL, M3UA_PORT, "127.0.0.2");
msc->msc_con->sccp_user =
osmo_sccp_user_bind(msc->msc_con->sccp, msc_name, sccp_sap_up, SCCP_SSN_BSSAP);
/* Start MSC reset procedure */
msc_reset(msc);
}
return 0;
}