From 0923fc6707ea35776ad8c37a6d490ac3408dd274 Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Wed, 12 Apr 2017 15:26:04 +0200 Subject: WIP: Integrate AoIP into OsmoBSC --- openbsc/configure.ac | 1 + openbsc/include/openbsc/Makefile.am | 1 + openbsc/include/openbsc/bsc_msc.h | 11 + openbsc/include/openbsc/bsc_msc_data.h | 7 + openbsc/include/openbsc/debug.h | 1 + openbsc/include/openbsc/osmo_bsc.h | 3 + openbsc/include/openbsc/osmo_bsc_sigtran.h | 39 ++++ openbsc/src/libcommon/debug.c | 6 + openbsc/src/osmo-bsc/Makefile.am | 3 + openbsc/src/osmo-bsc/osmo_bsc_api.c | 14 +- openbsc/src/osmo-bsc/osmo_bsc_bssap.c | 21 +- openbsc/src/osmo-bsc/osmo_bsc_main.c | 22 +- openbsc/src/osmo-bsc/osmo_bsc_msc.c | 62 ++++-- openbsc/src/osmo-bsc/osmo_bsc_sccp.c | 27 ++- openbsc/src/osmo-bsc/osmo_bsc_sigtran.c | 340 +++++++++++++++++++++++++++++ 15 files changed, 519 insertions(+), 39 deletions(-) create mode 100644 openbsc/include/openbsc/osmo_bsc_sigtran.h create mode 100644 openbsc/src/osmo-bsc/osmo_bsc_sigtran.c (limited to 'openbsc') diff --git a/openbsc/configure.ac b/openbsc/configure.ac index eccab2407..3875b1652 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -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) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 81c51aeba..1c31f743e 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -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 \ diff --git a/openbsc/include/openbsc/bsc_msc.h b/openbsc/include/openbsc/bsc_msc.h index 39258d364..8b9553bfa 100644 --- a/openbsc/include/openbsc/bsc_msc.h +++ b/openbsc/include/openbsc/bsc_msc.h @@ -24,6 +24,7 @@ #include #include +#include #include @@ -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); diff --git a/openbsc/include/openbsc/bsc_msc_data.h b/openbsc/include/openbsc/bsc_msc_data.h index 38e87cfb9..a819abab3 100644 --- a/openbsc/include/openbsc/bsc_msc_data.h +++ b/openbsc/include/openbsc/bsc_msc_data.h @@ -32,6 +32,13 @@ #include #include + +#include +#include +#include +#include +#include + #include struct osmo_bsc_rf; diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index de00b2930..65e197d52 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -40,6 +40,7 @@ enum { DPCU, DVLR, DIUCS, + DSIGTRAN, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/osmo_bsc.h b/openbsc/include/openbsc/osmo_bsc.h index 9e688fd59..5d3ff6a7f 100644 --- a/openbsc/include/openbsc/osmo_bsc.h +++ b/openbsc/include/openbsc/osmo_bsc.h @@ -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(); diff --git a/openbsc/include/openbsc/osmo_bsc_sigtran.h b/openbsc/include/openbsc/osmo_bsc_sigtran.h new file mode 100644 index 000000000..37085b653 --- /dev/null +++ b/openbsc/include/openbsc/osmo_bsc_sigtran.h @@ -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 . + * + */ + +#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); diff --git a/openbsc/src/libcommon/debug.c b/openbsc/src/libcommon/debug.c index 7c12159c4..7ed1e2934 100644 --- a/openbsc/src/libcommon/debug.c +++ b/openbsc/src/libcommon/debug.c @@ -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) diff --git a/openbsc/src/osmo-bsc/Makefile.am b/openbsc/src/osmo-bsc/Makefile.am index 6f836b08c..d0d0e3afc 100644 --- a/openbsc/src/osmo-bsc/Makefile.am +++ b/openbsc/src/osmo-bsc/Makefile.am @@ -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 \ @@ -53,4 +55,5 @@ osmo_bsc_LDADD = \ $(LIBOSMOCTRL_LIBS) \ $(COVERAGE_LDFLAGS) \ $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOSIGTRAN_LIBS) \ $(NULL) diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c index 8c33e2b57..d15ec40cd 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_api.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_api.c @@ -27,6 +27,7 @@ #include #include +#include #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; } diff --git a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c index 100f66441..57a62a5eb 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c @@ -29,6 +29,7 @@ #include #include +#include /* * 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; } diff --git a/openbsc/src/osmo-bsc/osmo_bsc_main.c b/openbsc/src/osmo-bsc/osmo_bsc_main.c index ee094d670..1f8f645ac 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_main.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -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); } diff --git a/openbsc/src/osmo-bsc/osmo_bsc_msc.c b/openbsc/src/osmo-bsc/osmo_bsc_msc.c index 8d02624b4..351fd2ced 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_msc.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_msc.c @@ -42,7 +42,7 @@ #include #include - +#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; } + diff --git a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c index e242390ef..f54dc31cb 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c @@ -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 diff --git a/openbsc/src/osmo-bsc/osmo_bsc_sigtran.c b/openbsc/src/osmo-bsc/osmo_bsc_sigtran.c new file mode 100644 index 000000000..b95ec9ddc --- /dev/null +++ b/openbsc/src/osmo-bsc/osmo_bsc_sigtran.c @@ -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 . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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() */ +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; +} -- cgit v1.2.3