aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bsc')
-rw-r--r--src/osmo-bsc/Makefile.am57
-rw-r--r--src/osmo-bsc/osmo_bsc_api.c569
-rw-r--r--src/osmo-bsc/osmo_bsc_audio.c141
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c721
-rw-r--r--src/osmo-bsc/osmo_bsc_ctrl.c680
-rw-r--r--src/osmo-bsc/osmo_bsc_filter.c381
-rw-r--r--src/osmo-bsc/osmo_bsc_grace.c169
-rw-r--r--src/osmo-bsc/osmo_bsc_main.c307
-rw-r--r--src/osmo-bsc/osmo_bsc_msc.c600
-rw-r--r--src/osmo-bsc/osmo_bsc_reset.c190
-rw-r--r--src/osmo-bsc/osmo_bsc_sigtran.c561
-rw-r--r--src/osmo-bsc/osmo_bsc_vty.c1039
12 files changed, 0 insertions, 5415 deletions
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
deleted file mode 100644
index 5642fb2ed..000000000
--- a/src/osmo-bsc/Makefile.am
+++ /dev/null
@@ -1,57 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/include \
- -I$(top_builddir) \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOGSM_CFLAGS) \
- $(LIBOSMOVTY_CFLAGS) \
- $(LIBOSMOCTRL_CFLAGS) \
- $(LIBOSMONETIF_CFLAGS) \
- $(LIBOSMOSCCP_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) \
- $(LIBOSMOSIGTRAN_CFLAGS) \
- $(NULL)
-
-AM_LDFLAGS = \
- $(COVERAGE_LDFLAGS) \
- $(NULL)
-
-bin_PROGRAMS = \
- osmo-bsc \
- $(NULL)
-
-osmo_bsc_SOURCES = \
- osmo_bsc_main.c \
- osmo_bsc_vty.c \
- osmo_bsc_api.c \
- osmo_bsc_grace.c \
- osmo_bsc_msc.c \
- osmo_bsc_sigtran.c \
- osmo_bsc_filter.c \
- osmo_bsc_bssap.c \
- osmo_bsc_audio.c \
- osmo_bsc_ctrl.c \
- $(NULL)
-
-# once again since TRAU uses CC symbol :(
-osmo_bsc_LDADD = \
- $(top_builddir)/src/libfilter/libfilter.a \
- $(top_builddir)/src/libbsc/libbsc.a \
- $(top_builddir)/src/libcommon-cs/libcommon-cs.a \
- $(top_builddir)/src/libmsc/libmsc.a \
- $(top_builddir)/src/libtrau/libtrau.a \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(LIBOSMOSCCP_LIBS) \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- $(LIBOSMOVTY_LIBS) \
- $(LIBOSMOCTRL_LIBS) \
- $(COVERAGE_LDFLAGS) \
- $(LIBOSMOABIS_LIBS) \
- $(LIBOSMOSIGTRAN_LIBS) \
- $(NULL)
diff --git a/src/osmo-bsc/osmo_bsc_api.c b/src/osmo-bsc/osmo_bsc_api.c
deleted file mode 100644
index f7343f743..000000000
--- a/src/osmo-bsc/osmo_bsc_api.c
+++ /dev/null
@@ -1,569 +0,0 @@
-/* (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2011 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <openbsc/osmo_bsc.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/debug.h>
-
-#include <openbsc/gsm_04_80.h>
-
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-#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) {\
- LOGP(DMSC, LOGL_ERROR, "MSC Connection not present.\n"); \
- return; \
- }
-
-#define return_when_not_connected_val(conn, ret) \
- if (!conn->sccp_con) {\
- LOGP(DMSC, LOGL_ERROR, "MSC Connection not present.\n"); \
- return ret; \
- }
-
-#define queue_msg_or_return(resp) \
- if (!resp) { \
- LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n"); \
- return; \
- } \
- 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,
- struct msgb *msg, struct bsc_msc_data *msc);
-
-static uint16_t get_network_code_for_msc(struct bsc_msc_data *msc)
-{
- if (msc->core_mnc != -1)
- return msc->core_mnc;
- return msc->network->network_code;
-}
-
-static uint16_t get_country_code_for_msc(struct bsc_msc_data *msc)
-{
- if (msc->core_mcc != -1)
- return msc->core_mcc;
- return msc->network->country_code;
-}
-
-static uint16_t get_lac_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts)
-{
- if (msc->core_lac != -1)
- return msc->core_lac;
- return bts->location_area_code;
-}
-
-static uint16_t get_ci_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts)
-{
- if (msc->core_ci != -1)
- return msc->core_ci;
- return bts->cell_identity;
-}
-
-static void bsc_maybe_lu_reject(struct gsm_subscriber_connection *conn, int con_type, int cause)
-{
- struct msgb *msg;
-
- /* ignore cm service request or such */
- if (con_type != FLT_CON_TYPE_LU)
- return;
-
- msg = gsm48_create_loc_upd_rej(cause);
- if (!msg) {
- LOGP(DMM, LOGL_ERROR, "Failed to create msg for LOCATION UPDATING REJECT.\n");
- return;
- }
-
- msg->lchan = conn->lchan;
- gsm0808_submit_dtap(conn, msg, 0, 0);
-}
-
-static int bsc_filter_initial(struct osmo_bsc_data *bsc,
- struct bsc_msc_data *msc,
- struct gsm_subscriber_connection *conn,
- struct msgb *msg, char **imsi, int *con_type,
- int *lu_cause)
-{
- struct bsc_filter_request req;
- struct bsc_filter_reject_cause cause;
- struct gsm48_hdr *gh = msgb_l3(msg);
- int rc;
-
- req.ctx = conn;
- req.black_list = NULL;
- req.access_lists = bsc_access_lists();
- req.local_lst_name = msc->acc_lst_name;
- req.global_lst_name = conn->bts->network->bsc_data->acc_lst_name;
- req.bsc_nr = 0;
-
- rc = bsc_msg_filter_initial(gh, msgb_l3len(msg), &req,
- con_type, imsi, &cause);
- *lu_cause = cause.lu_reject_cause;
- return rc;
-}
-
-static int bsc_filter_data(struct gsm_subscriber_connection *conn,
- struct msgb *msg, int *lu_cause)
-{
- struct bsc_filter_request req;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct bsc_filter_reject_cause cause;
- int rc;
-
- req.ctx = conn;
- req.black_list = NULL;
- req.access_lists = bsc_access_lists();
- req.local_lst_name = conn->sccp_con->msc->acc_lst_name;
- req.global_lst_name = conn->bts->network->bsc_data->acc_lst_name;
- req.bsc_nr = 0;
-
- rc = bsc_msg_filter_data(gh, msgb_l3len(msg), &req,
- &conn->sccp_con->filter_state,
- &cause);
- *lu_cause = cause.lu_reject_cause;
- return rc;
-}
-
-static void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
-{
- struct msgb *resp;
- return_when_not_connected(conn);
-
- LOGP(DMSC, LOGL_NOTICE, "Tx MSC SAPI N REJECT DLCI=0x%02x\n", dlci);
-
- resp = gsm0808_create_sapi_reject(dlci);
- queue_msg_or_return(resp);
-}
-
-static void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
- struct msgb *msg, uint8_t chosen_encr)
-{
- struct msgb *resp;
- return_when_not_connected(conn);
-
- LOGP(DMSC, LOGL_DEBUG, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
- resp = gsm0808_create_cipher_complete(msg, chosen_encr);
- queue_msg_or_return(resp);
-}
-
-static void bsc_send_ussd_no_srv(struct gsm_subscriber_connection *conn,
- struct msgb *msg, const char *text)
-{
- struct gsm48_hdr *gh;
- int8_t pdisc;
- uint8_t mtype;
- int drop_message = 1;
-
- if (!text)
- return;
-
- if (!msg || msgb_l3len(msg) < sizeof(*gh))
- return;
-
- gh = msgb_l3(msg);
- pdisc = gsm48_hdr_pdisc(gh);
- mtype = gsm48_hdr_msg_type(gh);
-
- /* Is CM service request? */
- if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) {
- struct gsm48_service_request *cm;
-
- cm = (struct gsm48_service_request *) &gh->data[0];
-
- /* Is type SMS or call? */
- if (cm->cm_service_type == GSM48_CMSERV_SMS)
- drop_message = 0;
- else if (cm->cm_service_type == GSM48_CMSERV_MO_CALL_PACKET)
- drop_message = 0;
- }
-
- if (drop_message) {
- LOGP(DMSC, LOGL_DEBUG, "Skipping (not sending) USSD message: '%s'\n", text);
- return;
- }
-
- LOGP(DMSC, LOGL_INFO, "Sending CM Service Accept\n");
- gsm48_tx_mm_serv_ack(conn);
-
- LOGP(DMSC, LOGL_INFO, "Sending USSD message: '%s'\n", text);
- bsc_send_ussd_notify(conn, 1, text);
- bsc_send_ussd_release_complete(conn);
-}
-
-/*
- * Instruct to reserve data for a new connectiom, create the complete
- * layer three message, send it to open the connection.
- */
-static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
- uint16_t chosen_channel)
-{
- struct bsc_msc_data *msc;
-
- LOGP(DMSC, LOGL_INFO, "Tx MSC COMPL L3\n");
-
- /* find the MSC link we want to use */
- msc = bsc_find_msc(conn, msg);
- if (!msc) {
- LOGP(DMSC, LOGL_ERROR, "Failed to find a MSC for a connection.\n");
- bsc_send_ussd_no_srv(conn, msg,
- conn->bts->network->bsc_data->ussd_no_msc_txt);
- return -1;
- }
-
- return complete_layer3(conn, msg, msc);
-}
-
-static int complete_layer3(struct gsm_subscriber_connection *conn,
- struct msgb *msg, struct bsc_msc_data *msc)
-{
- int con_type, rc, lu_cause;
- char *imsi = NULL;
- struct timeval tv;
- struct msgb *resp;
- uint16_t network_code;
- uint16_t country_code;
- uint16_t lac;
- uint16_t ci;
- enum bsc_con ret;
- int send_ping = msc->advanced_ping;
-
- /* Advanced ping/pong handling */
- if (osmo_timer_pending(&msc->pong_timer))
- send_ping = 0;
- if (msc->ping_timeout <= 0)
- send_ping = 0;
- if (send_ping && osmo_timer_remaining(&msc->ping_timer, NULL, &tv) == -1)
- send_ping = 0;
-
- /* Check the filter */
- rc = bsc_filter_initial(msc->network->bsc_data, msc, conn, msg,
- &imsi, &con_type, &lu_cause);
- if (rc < 0) {
- bsc_maybe_lu_reject(conn, con_type, lu_cause);
- return BSC_API_CONN_POL_REJECT;
- }
-
- /* allocate resource for a new connection */
- //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 */
- if (ret == BSC_CON_REJECT_NO_LINK)
- bsc_send_ussd_no_srv(conn, msg, msc->ussd_msc_lost_txt);
- else if (ret == BSC_CON_REJECT_RF_GRACE)
- bsc_send_ussd_no_srv(conn, msg, msc->ussd_grace_txt);
-
- return BSC_API_CONN_POL_REJECT;
- }
-
- if (imsi)
- conn->sccp_con->filter_state.imsi = talloc_steal(conn, imsi);
- conn->sccp_con->filter_state.con_type = con_type;
-
- /* check return value, if failed check msg for and send USSD */
-
- network_code = get_network_code_for_msc(conn->sccp_con->msc);
- country_code = get_country_code_for_msc(conn->sccp_con->msc);
- lac = get_lac_for_msc(conn->sccp_con->msc, conn->bts);
- ci = get_ci_for_msc(conn->sccp_con->msc, conn->bts);
-
- bsc_scan_bts_msg(conn, msg);
-
- resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci);
- if (!resp) {
- LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n");
- sccp_connection_free(conn->sccp_con->sccp);
- osmo_bsc_sigtran_del_conn(conn->sccp_con);
- return BSC_API_CONN_POL_REJECT;
- }
-
- if (osmo_bsc_sigtran_open_conn(conn->sccp_con, resp) != 0) {
- sccp_connection_free(conn->sccp_con->sccp);
- osmo_bsc_sigtran_del_conn(conn->sccp_con);
- msgb_free(resp);
- return BSC_API_CONN_POL_REJECT;
- }
-
- return BSC_API_CONN_POL_ACCEPT;
-}
-
-/*
- * Plastic surgery... we want to give up the current connection
- */
-static int move_to_msc(struct gsm_subscriber_connection *_conn,
- struct msgb *msg, struct bsc_msc_data *msc)
-{
- struct osmo_bsc_sccp_con *old_con = _conn->sccp_con;
-
- /*
- * 1. Give up the old connection.
- * This happens by sending a clear request to the MSC,
- * it should end with the MSC releasing the connection.
- */
- old_con->conn = NULL;
- bsc_clear_request(_conn, 0);
-
- /*
- * 2. Attempt to create a new connection to the local
- * MSC. If it fails the caller will need to handle this
- * properly.
- */
- _conn->sccp_con = NULL;
- if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) {
- gsm0808_clear(_conn);
- bsc_subscr_con_free(_conn);
- return 1;
- }
-
- return 2;
-}
-
-static int handle_cc_setup(struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- uint8_t pdisc = gsm48_hdr_pdisc(gh);
- uint8_t mtype = gsm48_hdr_msg_type(gh);
-
- struct bsc_msc_data *msc;
- struct gsm_mncc_number called;
- struct tlv_parsed tp;
- unsigned payload_len;
-
- char _dest_nr[35];
-
- /*
- * Do we have a setup message here? if not return fast.
- */
- if (pdisc != GSM48_PDISC_CC || mtype != GSM48_MT_CC_SETUP)
- return 0;
-
- payload_len = msgb_l3len(msg) - sizeof(*gh);
-
- tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
- if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
- LOGP(DMSC, LOGL_ERROR, "Called BCD not present in setup.\n");
- return -1;
- }
-
- memset(&called, 0, sizeof(called));
- gsm48_decode_called(&called,
- TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1);
-
- if (called.plan != 1 && called.plan != 0)
- return 0;
-
- if (called.plan == 1 && called.type == 1) {
- _dest_nr[0] = _dest_nr[1] = '0';
- memcpy(_dest_nr + 2, called.number, sizeof(called.number));
- } else
- memcpy(_dest_nr, called.number, sizeof(called.number));
-
- /*
- * Check if the connection should be moved...
- */
- llist_for_each_entry(msc, &conn->bts->network->bsc_data->mscs, entry) {
- if (msc->type != MSC_CON_TYPE_LOCAL)
- continue;
- if (!msc->local_pref)
- continue;
- if (regexec(&msc->local_pref_reg, _dest_nr, 0, NULL, 0) != 0)
- continue;
-
- return move_to_msc(conn, msg, msc);
- }
-
- return 0;
-}
-
-
-static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
-{
- int lu_cause;
- struct msgb *resp;
- return_when_not_connected(conn);
-
- LOGP(DMSC, LOGL_INFO, "Tx MSC DTAP LINK_ID=0x%02x\n", link_id);
-
- /*
- * We might want to move this connection to a new MSC. Ask someone
- * to handle it. If it was handled we will return.
- */
- if (handle_cc_setup(conn, msg) >= 1)
- return;
-
- /* Check the filter */
- if (bsc_filter_data(conn, msg, &lu_cause) < 0) {
- bsc_maybe_lu_reject(conn,
- conn->sccp_con->filter_state.con_type,
- lu_cause);
- bsc_clear_request(conn, 0);
- return;
- }
-
- bsc_scan_bts_msg(conn, msg);
-
- resp = gsm0808_create_dtap(msg, link_id);
- queue_msg_or_return(resp);
-}
-
-static void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_cause,
- uint8_t chosen_channel, uint8_t encr_alg_id,
- uint8_t speech_model)
-{
- struct msgb *resp;
- return_when_not_connected(conn);
-
- if (is_ipaccess_bts(conn->bts) && conn->sccp_con->rtp_ip) {
- /* NOTE: In a network that makes use of an IPA base station
- * and AoIP, we have to wait until the BTS reports its RTP
- * IP/Port combination back to BSC via RSL. Unfortunately, the
- * IPA protocol sends its Abis assignment complete message
- * before it sends its RTP IP/Port via IPACC. So we will now
- * postpone the AoIP assignment completed message until we
- * know the RTP IP/Port combination. */
- LOGP(DMSC, LOGL_INFO, "POSTPONE MSC ASSIGN COMPL\n");
- conn->lchan->abis_ip.ass_compl.rr_cause = rr_cause;
- conn->lchan->abis_ip.ass_compl.chosen_channel = chosen_channel;
- conn->lchan->abis_ip.ass_compl.encr_alg_id = encr_alg_id;
- conn->lchan->abis_ip.ass_compl.speech_mode = speech_model;
- conn->lchan->abis_ip.ass_compl.valid = true;
-
- } else {
- /* NOTE: Send the A assignment complete message immediately. */
- LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL\n");
- resp = gsm0808_create_assignment_completed(rr_cause, chosen_channel,
- encr_alg_id, speech_model);
- queue_msg_or_return(resp);
- }
-}
-
-static void bsc_assign_fail(struct gsm_subscriber_connection *conn,
- uint8_t cause, uint8_t *rr_cause)
-{
- struct msgb *resp;
- return_when_not_connected(conn);
-
- LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN FAIL\n");
-
- resp = gsm0808_create_assignment_failure(cause, rr_cause);
- queue_msg_or_return(resp);
-}
-
-static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
-{
- struct osmo_bsc_sccp_con *sccp;
- struct msgb *resp;
- return_when_not_connected_val(conn, 1);
-
- LOGP(DMSC, LOGL_INFO, "Tx MSC CLEAR REQUEST\n");
-
- /*
- * Remove the connection from BSC<->SCCP part, the SCCP part
- * will either be cleared by channel release or MSC disconnect
- */
- sccp = conn->sccp_con;
- sccp->conn = NULL;
- conn->sccp_con = NULL;
-
- resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE);
- if (!resp) {
- LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n");
- return 1;
- }
-
- osmo_bsc_sigtran_send(sccp, resp);
- return 1;
-}
-
-static void bsc_cm_update(struct gsm_subscriber_connection *conn,
- const uint8_t *cm2, uint8_t cm2_len,
- const uint8_t *cm3, uint8_t cm3_len)
-{
- struct msgb *resp;
- return_when_not_connected(conn);
-
- resp = gsm0808_create_classmark_update(cm2, cm2_len, cm3, cm3_len);
-
- queue_msg_or_return(resp);
-}
-
-static void bsc_mr_config(struct gsm_subscriber_connection *conn,
- struct gsm_lchan *lchan, int full_rate)
-{
- struct bsc_msc_data *msc;
- struct gsm48_multi_rate_conf *ms_conf, *bts_conf;
-
- if (!conn->sccp_con) {
- LOGP(DMSC, LOGL_ERROR,
- "No msc data available on conn %p. Audio will be broken.\n",
- conn);
- return;
- }
-
- msc = conn->sccp_con->msc;
-
- /* initialize the data structure */
- lchan->mr_ms_lv[0] = sizeof(*ms_conf);
- lchan->mr_bts_lv[0] = sizeof(*bts_conf);
- ms_conf = (struct gsm48_multi_rate_conf *) &lchan->mr_ms_lv[1];
- bts_conf = (struct gsm48_multi_rate_conf *) &lchan->mr_bts_lv[1];
- memset(ms_conf, 0, sizeof(*ms_conf));
- memset(bts_conf, 0, sizeof(*bts_conf));
-
- bts_conf->ver = ms_conf->ver = 1;
- bts_conf->icmi = ms_conf->icmi = 1;
-
- /* maybe gcc see's it is copy of _one_ byte */
- bts_conf->m4_75 = ms_conf->m4_75 = msc->amr_conf.m4_75;
- bts_conf->m5_15 = ms_conf->m5_15 = msc->amr_conf.m5_15;
- bts_conf->m5_90 = ms_conf->m5_90 = msc->amr_conf.m5_90;
- bts_conf->m6_70 = ms_conf->m6_70 = msc->amr_conf.m6_70;
- bts_conf->m7_40 = ms_conf->m7_40 = msc->amr_conf.m7_40;
- bts_conf->m7_95 = ms_conf->m7_95 = msc->amr_conf.m7_95;
- if (full_rate) {
- bts_conf->m10_2 = ms_conf->m10_2 = msc->amr_conf.m10_2;
- bts_conf->m12_2 = ms_conf->m12_2 = msc->amr_conf.m12_2;
- }
-
- /* now copy this into the bts structure */
- memcpy(lchan->mr_bts_lv, lchan->mr_ms_lv, sizeof(lchan->mr_ms_lv));
-}
-
-static struct bsc_api bsc_handler = {
- .sapi_n_reject = bsc_sapi_n_reject,
- .cipher_mode_compl = bsc_cipher_mode_compl,
- .compl_l3 = bsc_compl_l3,
- .dtap = bsc_dtap,
- .assign_compl = bsc_assign_compl,
- .assign_fail = bsc_assign_fail,
- .clear_request = bsc_clear_request,
- .classmark_chg = bsc_cm_update,
- .mr_config = bsc_mr_config,
-};
-
-struct bsc_api *osmo_bsc_api()
-{
- return &bsc_handler;
-}
diff --git a/src/osmo-bsc/osmo_bsc_audio.c b/src/osmo-bsc/osmo_bsc_audio.c
deleted file mode 100644
index b4ffa88f1..000000000
--- a/src/osmo-bsc/osmo_bsc_audio.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * ipaccess audio handling
- *
- * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2010 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/osmo_bsc.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-#include <osmocom/gsm/gsm0808.h>
-#include <osmocom/gsm/gsm0808_utils.h>
-#include <openbsc/osmo_bsc_sigtran.h>
-
-#include <arpa/inet.h>
-
-/* Generate and send assignment complete message */
-static int send_aoip_ass_compl(struct gsm_subscriber_connection *conn, struct gsm_lchan *lchan)
-{
- struct msgb *resp;
- struct sockaddr_storage rtp_addr;
- struct sockaddr_in rtp_addr_in;
- struct gsm0808_speech_codec sc;
-
- OSMO_ASSERT(lchan->abis_ip.ass_compl.valid == true);
-
- /* Package RTP-Address data */
- memset(&rtp_addr_in, 0, sizeof(rtp_addr_in));
- rtp_addr_in.sin_family = AF_INET;
- rtp_addr_in.sin_port = htons(lchan->abis_ip.bound_port);
- rtp_addr_in.sin_addr.s_addr = htonl(lchan->abis_ip.bound_ip);
- memset(&rtp_addr, 0, sizeof(rtp_addr));
- memcpy(&rtp_addr, &rtp_addr_in, sizeof(rtp_addr_in));
-
- /* Extrapolate speech codec from speech mode */
- gsm0808_speech_codec_from_chan_type(&sc, lchan->abis_ip.ass_compl.speech_mode);
-
- /* Generate message */
- resp = gsm0808_create_ass_compl(lchan->abis_ip.ass_compl.rr_cause,
- lchan->abis_ip.ass_compl.chosen_channel,
- lchan->abis_ip.ass_compl.encr_alg_id,
- lchan->abis_ip.ass_compl.speech_mode,
- &rtp_addr,
- &sc,
- NULL);
-
- if (!resp) {
- LOGP(DMSC, LOGL_ERROR, "Failed to generate assignment completed message!\n"); \
- return -EINVAL;
- }
-
- return osmo_bsc_sigtran_send(conn->sccp_con, resp);
-}
-
-static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct gsm_subscriber_connection *con;
- struct gsm_lchan *lchan = signal_data;
- int rc;
- uint32_t rtp_ip;
-
- if (subsys != SS_ABISIP)
- return 0;
-
- con = lchan->conn;
- if (!con || !con->sccp_con)
- return 0;
-
- switch (signal) {
- case S_ABISIP_CRCX_ACK:
- /*
- * TODO: handle handover here... then the audio should go to
- * the old mgcp port..
- */
-
- /* we can ask it to connect now */
- LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n",
- con->sccp_con->rtp_port, lchan->abis_ip.conn_id);
-
- /* If AoIP is in use, the rtp_ip, which has been communicated
- * via the A interface as connect_ip */
- if(con->sccp_con->rtp_ip)
- rtp_ip = con->sccp_con->rtp_ip;
- else
- rtp_ip = ntohl(INADDR_ANY);
-
- rc = rsl_ipacc_mdcx(lchan, rtp_ip,
- con->sccp_con->rtp_port,
- lchan->abis_ip.rtp_payload2);
- if (rc < 0) {
- LOGP(DMSC, LOGL_ERROR, "Failed to send MDCX: %d\n", rc);
- return rc;
- }
- break;
-
- case S_ABISIP_MDCX_ACK:
- if (con->ho_lchan) {
- /* NOTE: When an ho_lchan exists, the MDCX is part of an
- * handover operation (intra-bsc). This means we will not
- * inform the MSC about the event, which means that no
- * assignment complete message is transmitted */
- LOGP(DMSC, LOGL_INFO," RTP connection handover complete\n");
- } else if (is_ipaccess_bts(con->bts) && con->sccp_con->rtp_ip) {
- /* NOTE: This is only relevant on AoIP networks with
- * IPA based base stations. See also osmo_bsc_api.c,
- * function bsc_assign_compl() */
- LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL (POSTPONED)\n");
- if (send_aoip_ass_compl(con, lchan) != 0)
- return -EINVAL;
- }
- break;
- break;
- }
-
- return 0;
-}
-
-int osmo_bsc_audio_init(struct gsm_network *net)
-{
- osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, net);
- return 0;
-}
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
deleted file mode 100644
index 9a5288bdc..000000000
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ /dev/null
@@ -1,721 +0,0 @@
-/* GSM 08.08 BSSMAP handling */
-/* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2012 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <openbsc/osmo_bsc.h>
-#include <openbsc/osmo_bsc_grace.h>
-#include <openbsc/osmo_bsc_rf.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/bsc_subscriber.h>
-#include <osmocom/legacy_mgcp/mgcp.h>
-#include <openbsc/paging.h>
-
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-#include <osmocom/gsm/gsm0808.h>
-#include <osmocom/gsm/gsm0808_utils.h>
-#include <openbsc/osmo_bsc_sigtran.h>
-#include <openbsc/a_reset.h>
-#include <osmocom/core/byteswap.h>
-
-#define IP_V4_ADDR_LEN 4
-
-/*
- * helpers for the assignment command
- */
-
-/* Helper function for match_codec_pref(), looks up a matching permitted speech
- * value for a given msc audio codec pref */
-enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support
- *audio)
-{
- if (audio->hr) {
- switch (audio->ver) {
- case 1:
- return GSM0808_PERM_HR1;
- break;
- case 2:
- return GSM0808_PERM_HR2;
- break;
- case 3:
- return GSM0808_PERM_HR3;
- break;
- default:
- LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n",
- audio->ver);
- return GSM0808_PERM_FR1;
- }
- } else {
- switch (audio->ver) {
- case 1:
- return GSM0808_PERM_FR1;
- break;
- case 2:
- return GSM0808_PERM_FR2;
- break;
- case 3:
- return GSM0808_PERM_FR3;
- break;
- default:
- LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n",
- audio->ver);
- return GSM0808_PERM_HR1;
- }
- }
-}
-
-/* Helper function for match_codec_pref(), looks up a matching chan mode for
- * a given permitted speech value */
-enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
-{
- switch (speech) {
- case GSM0808_PERM_HR1:
- case GSM0808_PERM_FR1:
- return GSM48_CMODE_SPEECH_V1;
- break;
- case GSM0808_PERM_HR2:
- case GSM0808_PERM_FR2:
- return GSM48_CMODE_SPEECH_EFR;
- break;
- case GSM0808_PERM_HR3:
- case GSM0808_PERM_FR3:
- return GSM48_CMODE_SPEECH_AMR;
- break;
- default:
- LOGP(DMSC, LOGL_FATAL,
- "Unsupported permitted speech selected, assuming AMR as channel mode...\n");
- return GSM48_CMODE_SPEECH_AMR;
- }
-}
-
-/* Helper function for match_codec_pref(), tests if a given audio support
- * matches one of the permitted speech settings of the channel type element.
- * The matched permitted speech value is then also compared against the
- * speech codec list. (optional, only relevant for AoIP) */
-static bool test_codec_pref(const struct gsm0808_channel_type *ct,
- const struct gsm0808_speech_codec_list *scl,
- uint8_t perm_spch)
-{
- unsigned int i;
- bool match = false;
- struct gsm0808_speech_codec sc;
- int rc;
-
- /* Try to finde the given permitted speech value in the
- * codec list of the channel type element */
- for (i = 0; i < ct->perm_spch_len; i++) {
- if (ct->perm_spch[i] == perm_spch) {
- match = true;
- break;
- }
- }
-
- /* If we do not have a speech codec list to test against,
- * we just exit early (will be always the case in non-AoIP networks) */
- if (!scl)
- return match;
-
- /* If we failed to match until here, there is no
- * point in testing further */
- if (match == false)
- return false;
-
- /* Extrapolate speech codec data */
- rc = gsm0808_speech_codec_from_chan_type(&sc, perm_spch);
- if (rc < 0)
- return false;
-
- /* Try to find extrapolated speech codec data in
- * the speech codec list */
- for (i = 0; i < scl->len; i++) {
- if (memcmp(&sc, &scl->codec[i], sizeof(sc)) == 0)
- return true;
- }
-
- return false;
-}
-
-/* Helper function for bssmap_handle_assignm_req(), matches the codec
- * preferences from the MSC with the codec preferences */
-static int match_codec_pref(int *full_rate, enum gsm48_chan_mode *chan_mode,
- const struct gsm0808_channel_type *ct,
- const struct gsm0808_speech_codec_list *scl,
- const struct bsc_msc_data *msc)
-{
- unsigned int i;
- uint8_t perm_spch;
- bool match = false;
-
- for (i = 0; i < msc->audio_length; i++) {
- perm_spch = audio_support_to_gsm88(msc->audio_support[i]);
- if (test_codec_pref(ct, scl, perm_spch)) {
- match = true;
- break;
- }
- }
-
- /* Exit without result, in case no match can be deteched */
- if (!match) {
- *full_rate = -1;
- *chan_mode = GSM48_CMODE_SIGN;
- return -1;
- }
-
- /* Check if the result is a half or full rate codec */
- if (perm_spch == GSM0808_PERM_HR1 || perm_spch == GSM0808_PERM_HR2
- || perm_spch == GSM0808_PERM_HR3 || perm_spch == GSM0808_PERM_HR4
- || perm_spch == GSM0808_PERM_HR6)
- *full_rate = 0;
- else
- *full_rate = 1;
-
- /* Lookup a channel mode for the selected codec */
- *chan_mode = gsm88_to_chan_mode(perm_spch);
-
- return 0;
-}
-
-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: %s\n",
- osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance),
- &msc->a.msc_addr));
-
- /* Inform the FSM that controls the RESET/RESET-ACK procedure
- * that we have successfully received the reset-ack message */
- a_reset_ack_confirm(msc->a.reset);
-
- return 0;
-}
-
-/* Handle MSC sided reset */
-static int bssmap_handle_reset(struct bsc_msc_data *msc,
- struct msgb *msg, unsigned int length)
-{
- LOGP(DMSC, LOGL_NOTICE, "RESET from MSC: %s\n",
- osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance),
- &msc->a.msc_addr));
-
- /* Instruct the bsc to close all open sigtran connections and to
- * close all active channels on the BTS side as well */
- osmo_bsc_sigtran_reset(msc);
-
- /* Inform the MSC that we have received the reset request and
- * that we acted accordingly */
- osmo_bsc_sigtran_tx_reset_ack(msc);
-
- return 0;
-}
-
-/* GSM 08.08 ยง 3.2.1.19 */
-static int bssmap_handle_paging(struct bsc_msc_data *msc,
- struct msgb *msg, unsigned int payload_length)
-{
- struct bsc_subscr *subscr;
- struct tlv_parsed tp;
- char mi_string[GSM48_MI_SIZE];
- uint32_t tmsi = GSM_RESERVED_TMSI;
- unsigned int lac = GSM_LAC_RESERVED_ALL_BTS;
- uint8_t data_length;
- const uint8_t *data;
- uint8_t chan_needed = RSL_CHANNEED_ANY;
-
- tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
-
- if (!TLVP_PRESENT(&tp, GSM0808_IE_IMSI)) {
- LOGP(DMSC, LOGL_ERROR, "Mandatory IMSI not present.\n");
- return -1;
- } else if ((TLVP_VAL(&tp, GSM0808_IE_IMSI)[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) {
- LOGP(DMSC, LOGL_ERROR, "Wrong content in the IMSI\n");
- return -1;
- }
-
- if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
- LOGP(DMSC, LOGL_ERROR, "Mandatory CELL IDENTIFIER LIST not present.\n");
- return -1;
- }
-
- if (TLVP_PRESENT(&tp, GSM0808_IE_TMSI) &&
- TLVP_LEN(&tp, GSM0808_IE_TMSI) == 4) {
- tmsi = ntohl(tlvp_val32_unal(&tp, GSM0808_IE_TMSI));
- }
-
- /*
- * parse the IMSI
- */
- gsm48_mi_to_string(mi_string, sizeof(mi_string),
- TLVP_VAL(&tp, GSM0808_IE_IMSI), TLVP_LEN(&tp, GSM0808_IE_IMSI));
-
- /*
- * parse the cell identifier list
- */
- data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
- data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
-
- /*
- * Support paging to all network or one BTS at one LAC
- */
- if (data_length == 3 && data[0] == CELL_IDENT_LAC) {
- lac = osmo_load16be(&data[1]);
- } else if (data_length > 1 || (data[0] & 0x0f) != CELL_IDENT_BSS) {
- LOGP(DMSC, LOGL_ERROR, "Unsupported Cell Identifier List: %s\n", osmo_hexdump(data, data_length));
- return -1;
- }
-
- if (TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_NEEDED) && TLVP_LEN(&tp, GSM0808_IE_CHANNEL_NEEDED) == 1)
- chan_needed = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_NEEDED)[0] & 0x03;
-
- if (TLVP_PRESENT(&tp, GSM0808_IE_EMLPP_PRIORITY)) {
- LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n");
- }
-
- subscr = bsc_subscr_find_or_create_by_imsi(msc->network->bsc_subscribers,
- mi_string);
- if (!subscr) {
- LOGP(DMSC, LOGL_ERROR, "Failed to allocate a subscriber for %s\n", mi_string);
- return -1;
- }
-
- subscr->lac = lac;
- subscr->tmsi = tmsi;
-
- LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
- bsc_grace_paging_request(msc->network->bsc_data->rf_ctrl->policy,
- subscr, chan_needed, msc);
- return 0;
-}
-
-/*
- * GSM 08.08 ยง 3.1.9.1 and 3.2.1.21...
- * release our gsm_subscriber_connection and send message
- */
-static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
- struct msgb *msg, unsigned int payload_length)
-{
- struct msgb *resp;
-
- /* TODO: handle the cause of this package */
-
- if (conn->conn) {
- LOGP(DMSC, LOGL_INFO, "Releasing all transactions on %p\n", conn);
- gsm0808_clear(conn->conn);
- bsc_subscr_con_free(conn->conn);
- conn->conn = NULL;
- }
-
- /* send the clear complete message */
- resp = gsm0808_create_clear_complete();
- if (!resp) {
- LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n");
- return -1;
- }
-
- osmo_bsc_sigtran_send(conn, resp);
- return 0;
-}
-
-/*
- * GSM 08.08 ยง 3.4.7 cipher mode handling. We will have to pick
- * the cipher to be used for this. In case we are already using
- * a cipher we will have to send cipher mode reject to the MSC,
- * otherwise we will have to pick something that we and the MS
- * is supporting. Currently we are doing it in a rather static
- * way by picking one ecnryption or no encrytpion.
- */
-static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn,
- struct msgb *msg, unsigned int payload_length)
-{
- uint16_t len;
- struct gsm_network *network = NULL;
- const uint8_t *data;
- struct tlv_parsed tp;
- struct msgb *resp;
- int reject_cause = -1;
- int include_imeisv = 1;
-
- if (!conn->conn) {
- LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
- goto reject;
- }
-
- if (conn->ciphering_handled) {
- LOGP(DMSC, LOGL_ERROR, "Already seen ciphering command. Protocol Error.\n");
- goto reject;
- }
-
- conn->ciphering_handled = 1;
-
- tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
- if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) {
- LOGP(DMSC, LOGL_ERROR, "IE Encryption Information missing.\n");
- goto reject;
- }
-
- /*
- * check if our global setting is allowed
- * - Currently we check for A5/0 and A5/1
- * - Copy the key if that is necessary
- * - Otherwise reject
- */
- len = TLVP_LEN(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
- if (len < 1) {
- LOGP(DMSC, LOGL_ERROR, "IE Encryption Information is too short.\n");
- goto reject;
- }
-
- network = conn->conn->bts->network;
- data = TLVP_VAL(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
-
- if (TLVP_PRESENT(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE))
- include_imeisv = TLVP_VAL(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)[0] & 0x1;
-
- if (network->a5_encryption == 0 && (data[0] & 0x1) == 0x1) {
- gsm0808_cipher_mode(conn->conn, 0, NULL, 0, include_imeisv);
- } else if (network->a5_encryption != 0 && (data[0] & 0x2) == 0x2) {
- gsm0808_cipher_mode(conn->conn, 1, &data[1], len - 1, include_imeisv);
- } else {
- LOGP(DMSC, LOGL_ERROR, "Can not select encryption...\n");
- goto reject;
- }
-
- return 0;
-
-reject:
- resp = gsm0808_create_cipher_reject(reject_cause);
- if (!resp) {
- LOGP(DMSC, LOGL_ERROR, "Sending the cipher reject failed.\n");
- return -1;
- }
-
- osmo_bsc_sigtran_send(conn, resp);
- return -1;
-}
-
-/*
- * Handle the assignment request message.
- *
- * See ยง3.2.1.1 for the message type
- */
-static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
- struct msgb *msg, unsigned int length)
-{
- struct msgb *resp;
- struct bsc_msc_data *msc;
- struct tlv_parsed tp;
- uint8_t timeslot = 0;
- uint8_t multiplex = 0;
- enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;
- int port, full_rate = -1;
- bool aoip = false;
- struct sockaddr_storage rtp_addr;
- struct sockaddr_in *rtp_addr_in;
- struct gsm0808_channel_type ct;
- struct gsm0808_speech_codec_list scl;
- struct gsm0808_speech_codec_list *scl_ptr = NULL;
- int rc;
- const uint8_t *data;
- char len;
-
- if (!conn->conn) {
- LOGP(DMSC, LOGL_ERROR,
- "No lchan/msc_data in cipher mode command.\n");
- return -1;
- }
-
- msc = conn->msc;
-
- tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);
-
- /* Check for channel type element, if its missing, immediately reject */
- if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) {
- LOGP(DMSC, LOGL_ERROR, "Mandatory channel type not present.\n");
- goto reject;
- }
-
- /* Detect if a CIC code is present, if so, we use the classic ip.access
- * method to calculate the RTP port */
- if (TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
- conn->cic =
- osmo_load16be(TLVP_VAL
- (&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
- timeslot = conn->cic & 0x1f;
- multiplex = (conn->cic & ~0x1f) >> 5;
- } else if (TLVP_PRESENT(&tp, GSM0808_IE_AOIP_TRASP_ADDR)) {
- /* Decode AoIP transport address element */
- data = TLVP_VAL(&tp, GSM0808_IE_AOIP_TRASP_ADDR);
- len = TLVP_LEN(&tp, GSM0808_IE_AOIP_TRASP_ADDR);
- rc = gsm0808_dec_aoip_trasp_addr(&rtp_addr, data, len);
- if (rc < 0) {
- LOGP(DMSC, LOGL_ERROR,
- "Unable to decode aoip transport address.\n");
- goto reject;
- }
- aoip = true;
- } else {
- LOGP(DMSC, LOGL_ERROR,
- "transport address missing. Audio routing will not work.\n");
- goto reject;
- }
-
- /* Decode speech codec list (AoIP) */
- if (aoip) {
- /* Check for speech codec list element */
- if (!TLVP_PRESENT(&tp, GSM0808_IE_SPEECH_CODEC_LIST)) {
- LOGP(DMSC, LOGL_ERROR,
- "Mandatory speech codec list not present.\n");
- goto reject;
- }
-
- /* Decode Speech Codec list */
- data = TLVP_VAL(&tp, GSM0808_IE_SPEECH_CODEC_LIST);
- len = TLVP_LEN(&tp, GSM0808_IE_SPEECH_CODEC_LIST);
- rc = gsm0808_dec_speech_codec_list(&scl, data, len);
- if (rc < 0) {
- LOGP(DMSC, LOGL_ERROR,
- "Unable to decode speech codec list\n");
- goto reject;
- }
- scl_ptr = &scl;
- }
-
- /* Decode Channel Type element */
- data = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE);
- len = TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE);
- rc = gsm0808_dec_channel_type(&ct, data, len);
- if (rc < 0) {
- LOGP(DMSC, LOGL_ERROR, "unable to decode channel type.\n");
- goto reject;
- }
-
- /* Currently we only support a limited subset of all
- * possible channel types. The limitation ends by not using
- * multi-slot, limiting the channel coding to speech */
- if (ct.ch_indctr != GSM0808_CHAN_SPEECH) {
- LOGP(DMSC, LOGL_ERROR,
- "Unsupported channel type, currently only speech is supported!\n");
- goto reject;
- }
-
- /* Match codec information from the assignment command against the
- * local preferences of the BSC */
- rc = match_codec_pref(&full_rate, &chan_mode, &ct, scl_ptr, msc);
- if (rc < 0) {
- LOGP(DMSC, LOGL_ERROR, "No supported audio type found.\n");
- goto reject;
- }
-
- if (aoip == false) {
- /* map it to a MGCP Endpoint and a RTP port */
- port = mgcp_timeslot_to_endpoint(multiplex, timeslot);
- conn->rtp_port = rtp_calculate_port(port, msc->rtp_base);
- conn->rtp_ip = 0;
- } else {
- /* use address / port supplied with the AoIP
- * transport address element */
- if (rtp_addr.ss_family == AF_INET) {
- rtp_addr_in = (struct sockaddr_in *)&rtp_addr;
- conn->rtp_port = osmo_ntohs(rtp_addr_in->sin_port);
- memcpy(&conn->rtp_ip, &rtp_addr_in->sin_addr.s_addr,
- IP_V4_ADDR_LEN);
- conn->rtp_ip = osmo_ntohl(conn->rtp_ip);
- } else {
- LOGP(DMSC, LOGL_ERROR,
- "Unsopported addressing scheme. (supports only IPV4)\n");
- goto reject;
- }
- }
-
- return gsm0808_assign_req(conn->conn, chan_mode, full_rate);
-
-reject:
- resp =
- gsm0808_create_assignment_failure
- (GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
- if (!resp) {
- LOGP(DMSC, LOGL_ERROR, "Channel allocation failure.\n");
- return -1;
- }
-
- osmo_bsc_sigtran_send(conn, resp);
- return -1;
-}
-
-static int bssmap_rcvmsg_udt(struct bsc_msc_data *msc,
- struct msgb *msg, unsigned int length)
-{
- int ret = 0;
-
- if (length < 1) {
- LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
- return -1;
- }
-
- LOGP(DMSC, LOGL_INFO, "Rx MSC UDT BSSMAP %s\n",
- gsm0808_bssmap_name(msg->l4h[0]));
-
- switch (msg->l4h[0]) {
- case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
- ret = bssmap_handle_reset_ack(msc, msg, length);
- break;
- case BSS_MAP_MSG_RESET:
- ret = bssmap_handle_reset(msc, msg, length);
- break;
- case BSS_MAP_MSG_PAGING:
- ret = bssmap_handle_paging(msc, msg, length);
- break;
- }
-
- return ret;
-}
-
-static int bssmap_rcvmsg_dt1(struct osmo_bsc_sccp_con *conn,
- struct msgb *msg, unsigned int length)
-{
- int ret = 0;
-
- if (length < 1) {
- LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
- return -1;
- }
-
- LOGP(DMSC, LOGL_INFO, "Rx MSC DT1 BSSMAP %s\n",
- gsm0808_bssmap_name(msg->l4h[0]));
-
- switch (msg->l4h[0]) {
- case BSS_MAP_MSG_CLEAR_CMD:
- ret = bssmap_handle_clear_command(conn, msg, length);
- break;
- case BSS_MAP_MSG_CIPHER_MODE_CMD:
- ret = bssmap_handle_cipher_mode(conn, msg, length);
- break;
- case BSS_MAP_MSG_ASSIGMENT_RQST:
- ret = bssmap_handle_assignm_req(conn, msg, length);
- break;
- default:
- LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",
- gsm0808_bssmap_name(msg->l4h[0]));
- break;
- }
-
- return ret;
-}
-
-static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn,
- struct msgb *msg, unsigned int length)
-{
- struct dtap_header *header;
- struct msgb *gsm48;
- uint8_t *data;
- int rc, dtap_rc;
-
- LOGP(DMSC, LOGL_DEBUG, "Rx MSC DTAP: %s\n",
- osmo_hexdump(msg->l3h, length));
-
- if (!conn->conn) {
- LOGP(DMSC, LOGL_ERROR, "No subscriber connection available\n");
- return -1;
- }
-
- header = (struct dtap_header *) msg->l3h;
- if (sizeof(*header) >= length) {
- LOGP(DMSC, LOGL_ERROR, "The DTAP header does not fit. Wanted: %zu got: %u\n", sizeof(*header), length);
- LOGP(DMSC, LOGL_ERROR, "hex: %s\n", osmo_hexdump(msg->l3h, length));
- return -1;
- }
-
- if (header->length > length - sizeof(*header)) {
- LOGP(DMSC, LOGL_ERROR, "The DTAP l4 information does not fit: header: %u length: %u\n", header->length, length);
- LOGP(DMSC, LOGL_ERROR, "hex: %s\n", osmo_hexdump(msg->l3h, length));
- return -1;
- }
-
- LOGP(DMSC, LOGL_INFO, "Rx MSC DTAP, SAPI: %u CHAN: %u\n", header->link_id & 0x07, header->link_id & 0xC0);
-
- /* forward the data */
- gsm48 = gsm48_msgb_alloc_name("GSM 04.08 DTAP RCV");
- if (!gsm48) {
- LOGP(DMSC, LOGL_ERROR, "Allocation of the message failed.\n");
- return -1;
- }
-
- gsm48->l3h = gsm48->data;
- data = msgb_put(gsm48, length - sizeof(*header));
- memcpy(data, msg->l3h + sizeof(*header), length - sizeof(*header));
-
- /* pass it to the filter for extra actions */
- rc = bsc_scan_msc_msg(conn->conn, gsm48);
- dtap_rc = gsm0808_submit_dtap(conn->conn, gsm48, header->link_id, 1);
- if (rc == BSS_SEND_USSD)
- bsc_send_welcome_ussd(conn->conn);
- return dtap_rc;
-}
-
-int bsc_handle_udt(struct bsc_msc_data *msc,
- struct msgb *msgb, unsigned int length)
-{
- struct bssmap_header *bs;
-
- LOGP(DMSC, LOGL_DEBUG, "Rx MSC UDT: %s\n",
- osmo_hexdump(msgb->l3h, length));
-
- if (length < sizeof(*bs)) {
- LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
- return -1;
- }
-
- bs = (struct bssmap_header *) msgb->l3h;
- if (bs->length < length - sizeof(*bs))
- return -1;
-
- switch (bs->type) {
- case BSSAP_MSG_BSS_MANAGEMENT:
- msgb->l4h = &msgb->l3h[sizeof(*bs)];
- bssmap_rcvmsg_udt(msc, msgb, length - sizeof(*bs));
- break;
- default:
- LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",
- gsm0808_bssmap_name(bs->type));
- }
-
- return 0;
-}
-
-int bsc_handle_dt(struct osmo_bsc_sccp_con *conn,
- struct msgb *msg, unsigned int len)
-{
- if (len < sizeof(struct bssmap_header)) {
- LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
- }
-
- switch (msg->l3h[0]) {
- case BSSAP_MSG_BSS_MANAGEMENT:
- msg->l4h = &msg->l3h[sizeof(struct bssmap_header)];
- bssmap_rcvmsg_dt1(conn, msg, len - sizeof(struct bssmap_header));
- break;
- case BSSAP_MSG_DTAP:
- dtap_rcvmsg(conn, msg, len);
- break;
- default:
- LOGP(DMSC, LOGL_NOTICE, "Unimplemented BSSAP msg type: %s\n",
- gsm0808_bssap_name(msg->l3h[0]));
- }
-
- return -1;
-}
diff --git a/src/osmo-bsc/osmo_bsc_ctrl.c b/src/osmo-bsc/osmo_bsc_ctrl.c
deleted file mode 100644
index c23ed2187..000000000
--- a/src/osmo-bsc/osmo_bsc_ctrl.c
+++ /dev/null
@@ -1,680 +0,0 @@
-/* (C) 2011 by Daniel Willmann <daniel@totalueberwachung.de>
- * (C) 2011 by Holger Hans Peter Freyther
- * (C) 2011 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <osmocom/ctrl/control_cmd.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/osmo_bsc.h>
-#include <openbsc/osmo_bsc_rf.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/signal.h>
-#include <openbsc/gsm_04_80.h>
-
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/signal.h>
-#include <osmocom/core/talloc.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_connection *msc_con)
-{
- struct ctrl_cmd *trap;
- struct ctrl_handle *ctrl;
- struct bsc_msc_data *msc_data;
-
- msc_data = (struct bsc_msc_data *) msc_con->write_queue.bfd.data;
- ctrl = msc_data->network->ctrl;
-
- trap = ctrl_cmd_trap(cmd);
- if (!trap) {
- LOGP(DCTRL, LOGL_ERROR, "Failed to create trap.\n");
- return;
- }
-
- ctrl_cmd_send_to_all(ctrl, trap);
- ctrl_cmd_send(&msc_con->write_queue, trap);
-
- talloc_free(trap);
-}
-
-CTRL_CMD_DEFINE_RO(msc_connection_status, "msc_connection_status");
-static int msc_connection_status = 0;
-
-static int get_msc_connection_status(struct ctrl_cmd *cmd, void *data)
-{
- if (msc_connection_status)
- cmd->reply = "connected";
- else
- cmd->reply = "disconnected";
- return CTRL_CMD_REPLY;
-}
-
-static int msc_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
-{
- struct ctrl_cmd *cmd;
- struct gsm_network *gsmnet = (struct gsm_network *)handler_data;
-
- if (signal == S_MSC_LOST && msc_connection_status == 1) {
- LOGP(DCTRL, LOGL_DEBUG, "MSC connection lost, sending TRAP.\n");
- msc_connection_status = 0;
- } else if (signal == S_MSC_CONNECTED && msc_connection_status == 0) {
- LOGP(DCTRL, LOGL_DEBUG, "MSC connection (re)established, sending TRAP.\n");
- msc_connection_status = 1;
- } else {
- return 0;
- }
-
- cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
- if (!cmd) {
- LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n");
- return 0;
- }
-
- cmd->id = "0";
- cmd->variable = "msc_connection_status";
-
- get_msc_connection_status(cmd, NULL);
-
- ctrl_cmd_send_to_all(gsmnet->ctrl, cmd);
-
- talloc_free(cmd);
-
- return 0;
-}
-
-CTRL_CMD_DEFINE_RO(bts_connection_status, "bts_connection_status");
-static int bts_connection_status = 0;
-
-static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data)
-{
- if (bts_connection_status)
- cmd->reply = "connected";
- else
- cmd->reply = "disconnected";
- return CTRL_CMD_REPLY;
-}
-
-static int bts_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
-{
- struct ctrl_cmd *cmd;
- struct gsm_network *gsmnet = (struct gsm_network *)handler_data;
- struct gsm_bts *bts;
- int bts_current_status;
-
- if (signal != S_L_INP_TEI_DN && signal != S_L_INP_TEI_UP) {
- return 0;
- }
-
- bts_current_status = 0;
- /* Check if OML on at least one BTS is up */
- llist_for_each_entry(bts, &gsmnet->bts_list, list) {
- if (bts->oml_link) {
- bts_current_status = 1;
- break;
- }
- }
- if (bts_connection_status == 0 && bts_current_status == 1) {
- LOGP(DCTRL, LOGL_DEBUG, "BTS connection (re)established, sending TRAP.\n");
- } else if (bts_connection_status == 1 && bts_current_status == 0) {
- LOGP(DCTRL, LOGL_DEBUG, "No more BTS connected, sending TRAP.\n");
- } else {
- return 0;
- }
-
- cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
- if (!cmd) {
- LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n");
- return 0;
- }
-
- bts_connection_status = bts_current_status;
-
- cmd->id = "0";
- cmd->variable = "bts_connection_status";
-
- get_bts_connection_status(cmd, NULL);
-
- ctrl_cmd_send_to_all(gsmnet->ctrl, cmd);
-
- talloc_free(cmd);
-
- return 0;
-}
-
-static int get_bts_loc(struct ctrl_cmd *cmd, void *data);
-
-static void generate_location_state_trap(struct gsm_bts *bts, struct bsc_msc_connection *msc_con)
-{
- struct ctrl_cmd *cmd;
- const char *oper, *admin, *policy;
-
- cmd = ctrl_cmd_create(msc_con, CTRL_TYPE_TRAP);
- if (!cmd) {
- LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n");
- return;
- }
-
- cmd->id = "0";
- cmd->variable = talloc_asprintf(cmd, "bts.%i.location-state", bts->nr);
-
- /* Prepare the location reply */
- cmd->node = bts;
- get_bts_loc(cmd, NULL);
-
- oper = osmo_bsc_rf_get_opstate_name(osmo_bsc_rf_get_opstate_by_bts(bts));
- admin = osmo_bsc_rf_get_adminstate_name(osmo_bsc_rf_get_adminstate_by_bts(bts));
- policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts));
-
- cmd->reply = talloc_asprintf_append(cmd->reply,
- ",%s,%s,%s,%d,%d",
- oper, admin, policy,
- bts->network->country_code,
- bts->network->network_code);
-
- osmo_bsc_send_trap(cmd, msc_con);
- talloc_free(cmd);
-}
-
-void bsc_gen_location_state_trap(struct gsm_bts *bts)
-{
- struct bsc_msc_data *msc;
-
- llist_for_each_entry(msc, &bts->network->bsc_data->mscs, entry)
- generate_location_state_trap(bts, msc->msc_con);
-}
-
-static int location_equal(struct bts_location *a, struct bts_location *b)
-{
- return ((a->tstamp == b->tstamp) && (a->valid == b->valid) && (a->lat == b->lat) &&
- (a->lon == b->lon) && (a->height == b->height));
-}
-
-static void cleanup_locations(struct llist_head *locations)
-{
- struct bts_location *myloc, *tmp;
- int invalpos = 0, i = 0;
-
- LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n");
- llist_for_each_entry_safe(myloc, tmp, locations, list) {
- i++;
- if (i > 3) {
- LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n");
- llist_del(&myloc->list);
- talloc_free(myloc);
- } else if (myloc->valid == BTS_LOC_FIX_INVALID) {
- /* Only capture the newest of subsequent invalid positions */
- invalpos++;
- if (invalpos > 1) {
- LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n");
- invalpos--;
- i--;
- llist_del(&myloc->list);
- talloc_free(myloc);
- }
- } else {
- invalpos = 0;
- }
- }
- LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i);
-}
-
-CTRL_CMD_DEFINE(bts_loc, "location");
-static int get_bts_loc(struct ctrl_cmd *cmd, void *data)
-{
- struct bts_location *curloc;
- struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
- if (!bts) {
- cmd->reply = "bts not found.";
- return CTRL_CMD_ERROR;
- }
-
- if (llist_empty(&bts->loc_list)) {
- cmd->reply = talloc_asprintf(cmd, "0,invalid,0,0,0");
- return CTRL_CMD_REPLY;
- } else {
- curloc = llist_entry(bts->loc_list.next, struct bts_location, list);
- }
-
- cmd->reply = talloc_asprintf(cmd, "%lu,%s,%f,%f,%f", curloc->tstamp,
- get_value_string(bts_loc_fix_names, curloc->valid), curloc->lat, curloc->lon, curloc->height);
- if (!cmd->reply) {
- cmd->reply = "OOM";
- return CTRL_CMD_ERROR;
- }
-
- return CTRL_CMD_REPLY;
-}
-
-static int set_bts_loc(struct ctrl_cmd *cmd, void *data)
-{
- char *saveptr, *lat, *lon, *height, *tstamp, *valid, *tmp;
- struct bts_location *curloc, *lastloc;
- int ret;
- struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
- if (!bts) {
- cmd->reply = "bts not found.";
- return CTRL_CMD_ERROR;
- }
-
- tmp = talloc_strdup(cmd, cmd->value);
- if (!tmp)
- goto oom;
-
- curloc = talloc_zero(tall_bsc_ctx, struct bts_location);
- if (!curloc) {
- talloc_free(tmp);
- goto oom;
- }
- INIT_LLIST_HEAD(&curloc->list);
-
-
- tstamp = strtok_r(tmp, ",", &saveptr);
- valid = strtok_r(NULL, ",", &saveptr);
- lat = strtok_r(NULL, ",", &saveptr);
- lon = strtok_r(NULL, ",", &saveptr);
- height = strtok_r(NULL, "\0", &saveptr);
-
- curloc->tstamp = atol(tstamp);
- curloc->valid = get_string_value(bts_loc_fix_names, valid);
- curloc->lat = atof(lat);
- curloc->lon = atof(lon);
- curloc->height = atof(height);
- talloc_free(tmp);
-
- lastloc = llist_entry(bts->loc_list.next, struct bts_location, list);
-
- /* Add location to the end of the list */
- llist_add(&curloc->list, &bts->loc_list);
-
- ret = get_bts_loc(cmd, data);
-
- if (!location_equal(curloc, lastloc))
- bsc_gen_location_state_trap(bts);
-
- cleanup_locations(&bts->loc_list);
-
- return ret;
-
-oom:
- cmd->reply = "OOM";
- return CTRL_CMD_ERROR;
-}
-
-static int verify_bts_loc(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- char *saveptr, *latstr, *lonstr, *heightstr, *tstampstr, *validstr, *tmp;
- time_t tstamp;
- int valid;
- double lat, lon, height __attribute__((unused));
-
- tmp = talloc_strdup(cmd, value);
- if (!tmp)
- return 1;
-
- tstampstr = strtok_r(tmp, ",", &saveptr);
- validstr = strtok_r(NULL, ",", &saveptr);
- latstr = strtok_r(NULL, ",", &saveptr);
- lonstr = strtok_r(NULL, ",", &saveptr);
- heightstr = strtok_r(NULL, "\0", &saveptr);
-
- if ((tstampstr == NULL) || (validstr == NULL) || (latstr == NULL) ||
- (lonstr == NULL) || (heightstr == NULL))
- goto err;
-
- tstamp = atol(tstampstr);
- valid = get_string_value(bts_loc_fix_names, validstr);
- lat = atof(latstr);
- lon = atof(lonstr);
- height = atof(heightstr);
- talloc_free(tmp);
- tmp = NULL;
-
- if (((tstamp == 0) && (valid != BTS_LOC_FIX_INVALID)) || (lat < -90) || (lat > 90) ||
- (lon < -180) || (lon > 180) || (valid < 0)) {
- goto err;
- }
-
- return 0;
-
-err:
- talloc_free(tmp);
- cmd->reply = talloc_strdup(cmd, "The format is <unixtime>,(invalid|fix2d|fix3d),<lat>,<lon>,<height>");
- return 1;
-}
-
-CTRL_CMD_DEFINE(net_timezone, "timezone");
-static int get_net_timezone(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_network *net = (struct gsm_network*)cmd->node;
-
- struct gsm_tz *tz = &net->tz;
- if (tz->override)
- cmd->reply = talloc_asprintf(cmd, "%d,%d,%d",
- tz->hr, tz->mn, tz->dst);
- else
- cmd->reply = talloc_asprintf(cmd, "off");
-
- if (!cmd->reply) {
- cmd->reply = "OOM";
- return CTRL_CMD_ERROR;
- }
-
- return CTRL_CMD_REPLY;
-}
-
-static int set_net_timezone(struct ctrl_cmd *cmd, void *data)
-{
- char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0;
- int override;
- struct gsm_network *net = (struct gsm_network*)cmd->node;
-
- tmp = talloc_strdup(cmd, cmd->value);
- if (!tmp)
- goto oom;
-
- hourstr = strtok_r(tmp, ",", &saveptr);
- minstr = strtok_r(NULL, ",", &saveptr);
- dststr = strtok_r(NULL, ",", &saveptr);
-
- override = 0;
-
- if (hourstr != NULL)
- override = strcasecmp(hourstr, "off") != 0;
-
- struct gsm_tz *tz = &net->tz;
- tz->override = override;
-
- if (override) {
- tz->hr = hourstr ? atol(hourstr) : 0;
- tz->mn = minstr ? atol(minstr) : 0;
- tz->dst = dststr ? atol(dststr) : 0;
- }
-
- talloc_free(tmp);
- tmp = NULL;
-
- return get_net_timezone(cmd, data);
-
-oom:
- cmd->reply = "OOM";
- return CTRL_CMD_ERROR;
-}
-
-static int verify_net_timezone(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- char *saveptr, *hourstr, *minstr, *dststr, *tmp;
- int override, tz_hours, tz_mins, tz_dst;
-
- tmp = talloc_strdup(cmd, value);
- if (!tmp)
- return 1;
-
- hourstr = strtok_r(tmp, ",", &saveptr);
- minstr = strtok_r(NULL, ",", &saveptr);
- dststr = strtok_r(NULL, ",", &saveptr);
-
- if (hourstr == NULL)
- goto err;
-
- override = strcasecmp(hourstr, "off") != 0;
-
- if (!override) {
- talloc_free(tmp);
- return 0;
- }
-
- if (minstr == NULL || dststr == NULL)
- goto err;
-
- tz_hours = atol(hourstr);
- tz_mins = atol(minstr);
- tz_dst = atol(dststr);
-
- talloc_free(tmp);
- tmp = NULL;
-
- if ((tz_hours < -19) || (tz_hours > 19) ||
- (tz_mins < 0) || (tz_mins >= 60) || (tz_mins % 15 != 0) ||
- (tz_dst < 0) || (tz_dst > 2))
- goto err;
-
- return 0;
-
-err:
- talloc_free(tmp);
- cmd->reply = talloc_strdup(cmd, "The format is <hours>,<mins>,<dst> or 'off' where -19 <= hours <= 19, mins in {0, 15, 30, 45}, and 0 <= dst <= 2");
- return 1;
-}
-
-CTRL_CMD_DEFINE(net_notification, "notification");
-static int get_net_notification(struct ctrl_cmd *cmd, void *data)
-{
- cmd->reply = "There is nothing to read";
- return CTRL_CMD_ERROR;
-}
-
-static int set_net_notification(struct ctrl_cmd *cmd, void *data)
-{
- struct ctrl_cmd *trap;
- struct gsm_network *net;
-
- net = cmd->node;
-
- trap = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
- if (!trap) {
- LOGP(DCTRL, LOGL_ERROR, "Trap creation failed\n");
- goto handled;
- }
-
- trap->id = "0";
- trap->variable = "notification";
- trap->reply = talloc_strdup(trap, cmd->value);
-
- /*
- * This should only be sent to local systems. In the future
- * we might even ask for systems to register to receive
- * the notifications.
- */
- ctrl_cmd_send_to_all(net->ctrl, trap);
- talloc_free(trap);
-
-handled:
- return CTRL_CMD_HANDLED;
-}
-
-static int verify_net_notification(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- return 0;
-}
-
-CTRL_CMD_DEFINE(net_inform_msc, "inform-msc-v1");
-static int get_net_inform_msc(struct ctrl_cmd *cmd, void *data)
-{
- cmd->reply = "There is nothing to read";
- return CTRL_CMD_ERROR;
-}
-
-static int set_net_inform_msc(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_network *net;
- struct bsc_msc_data *msc;
-
- net = cmd->node;
- llist_for_each_entry(msc, &net->bsc_data->mscs, entry) {
- struct ctrl_cmd *trap;
-
- trap = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
- if (!trap) {
- LOGP(DCTRL, LOGL_ERROR, "Trap creation failed\n");
- continue;
- }
-
- trap->id = "0";
- trap->variable = "inform-msc-v1";
- trap->reply = talloc_strdup(trap, cmd->value);
- ctrl_cmd_send(&msc->msc_con->write_queue, trap);
- talloc_free(trap);
- }
-
-
- return CTRL_CMD_HANDLED;
-}
-
-static int verify_net_inform_msc(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- return 0;
-}
-
-CTRL_CMD_DEFINE(net_ussd_notify, "ussd-notify-v1");
-static int get_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
-{
- cmd->reply = "There is nothing to read";
- return CTRL_CMD_ERROR;
-}
-
-static int set_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_subscriber_connection *conn;
- struct gsm_network *net;
- char *saveptr = NULL;
- char *cic_str, *alert_str, *text_str;
- int cic, alert;
-
- /* Verify has done the test for us */
- cic_str = strtok_r(cmd->value, ",", &saveptr);
- alert_str = strtok_r(NULL, ",", &saveptr);
- text_str = strtok_r(NULL, ",", &saveptr);
-
- if (!cic_str || !alert_str || !text_str) {
- cmd->reply = "Programming issue. How did this pass verify?";
- return CTRL_CMD_ERROR;
- }
-
- cmd->reply = "No connection found";
-
- cic = atoi(cic_str);
- alert = atoi(alert_str);
-
- net = cmd->node;
- llist_for_each_entry(conn, &net->subscr_conns, entry) {
- if (!conn->sccp_con)
- continue;
-
- if (conn->sccp_con->cic != cic)
- continue;
-
- /*
- * This is a hack. My E71 does not like to immediately
- * receive a release complete on a TCH. So schedule a
- * release complete to clear any previous attempt. The
- * right thing would be to track invokeId and only send
- * the release complete when we get a returnResultLast
- * for this invoke id.
- */
- bsc_send_ussd_release_complete(conn);
- bsc_send_ussd_notify(conn, alert, text_str);
- cmd->reply = "Found a connection";
- break;
- }
-
- return CTRL_CMD_REPLY;
-}
-
-static int verify_net_ussd_notify(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- char *saveptr = NULL;
- char *inp, *cic, *alert, *text;
-
- OSMO_ASSERT(cmd);
- inp = talloc_strdup(cmd, value);
-
- cic = strtok_r(inp, ",", &saveptr);
- alert = strtok_r(NULL, ",", &saveptr);
- text = strtok_r(NULL, ",", &saveptr);
-
- talloc_free(inp);
- if (!cic || !alert || !text)
- return 1;
- return 0;
-}
-
-static int msc_signal_handler(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct msc_signal_data *msc;
- struct gsm_network *net;
- struct gsm_bts *bts;
-
- if (subsys != SS_MSC)
- return 0;
- if (signal != S_MSC_AUTHENTICATED)
- return 0;
-
- msc = signal_data;
-
- net = msc->data->network;
- llist_for_each_entry(bts, &net->bts_list, list)
- generate_location_state_trap(bts, msc->data->msc_con);
-
- return 0;
-}
-
-int bsc_ctrl_cmds_install(struct gsm_network *net)
-{
- int rc;
-
- rc = bsc_base_ctrl_cmds_install();
- if (rc)
- goto end;
- rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc);
- if (rc)
- goto end;
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_timezone);
- if (rc)
- goto end;
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_msc_connection_status);
- if (rc)
- goto end;
- rc = osmo_signal_register_handler(SS_MSC, &msc_connection_status_trap_cb, net);
- if (rc)
- goto end;
- rc = osmo_signal_register_handler(SS_MSC, msc_signal_handler, NULL);
- if (rc)
- goto end;
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_bts_connection_status);
- if (rc)
- goto end;
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_notification);
- if (rc)
- goto end;
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_inform_msc);
- if (rc)
- goto end;
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_ussd_notify);
- if (rc)
- goto end;
- rc = osmo_signal_register_handler(SS_L_INPUT, &bts_connection_status_trap_cb, net);
-
-end:
- return rc;
-}
diff --git a/src/osmo-bsc/osmo_bsc_filter.c b/src/osmo-bsc/osmo_bsc_filter.c
deleted file mode 100644
index 2c84b169f..000000000
--- a/src/osmo-bsc/osmo_bsc_filter.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2011 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <openbsc/osmo_bsc.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/gsm_04_80.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/bsc_subscriber.h>
-#include <openbsc/debug.h>
-#include <openbsc/paging.h>
-
-#include <stdlib.h>
-
-static void handle_lu_request(struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- struct gsm48_hdr *gh;
- struct gsm48_loc_upd_req *lu;
- struct gsm48_loc_area_id lai;
- struct gsm_network *net;
-
- if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) {
- LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg));
- return;
- }
-
- net = conn->bts->network;
-
- gh = msgb_l3(msg);
- lu = (struct gsm48_loc_upd_req *) gh->data;
-
- gsm48_generate_lai(&lai, net->country_code, net->network_code,
- conn->bts->location_area_code);
-
- if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) {
- LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n");
- conn->sccp_con->new_subscriber = 1;
- }
-}
-
-/* extract a subscriber from the paging response */
-static struct bsc_subscr *extract_sub(struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- uint8_t mi_type;
- char mi_string[GSM48_MI_SIZE];
- struct gsm48_hdr *gh;
- struct gsm48_pag_resp *resp;
- struct bsc_subscr *subscr;
-
- if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) {
- LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg));
- return NULL;
- }
-
- gh = msgb_l3(msg);
- resp = (struct gsm48_pag_resp *) &gh->data[0];
-
- gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
- mi_string, &mi_type);
- DEBUGP(DRR, "PAGING RESPONSE: MI(%s)=%s\n",
- gsm48_mi_type_name(mi_type), mi_string);
-
- switch (mi_type) {
- case GSM_MI_TYPE_TMSI:
- subscr = bsc_subscr_find_by_tmsi(conn->network->bsc_subscribers,
- tmsi_from_string(mi_string));
- break;
- case GSM_MI_TYPE_IMSI:
- subscr = bsc_subscr_find_by_imsi(conn->network->bsc_subscribers,
- mi_string);
- break;
- default:
- subscr = NULL;
- break;
- }
-
- return subscr;
-}
-
-/* we will need to stop the paging request */
-static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
-{
- struct bsc_subscr *subscr = extract_sub(conn, msg);
-
- if (!subscr) {
- LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
- return -1;
- }
-
- paging_request_stop(&conn->network->bts_list, conn->bts, subscr, conn,
- msg);
- bsc_subscr_put(subscr);
- return 0;
-}
-
-static int is_cm_service_for_emerg(struct msgb *msg)
-{
- struct gsm48_service_request *cm;
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*cm)) {
- LOGP(DMSC, LOGL_ERROR, "CM ServiceRequest does not fit.\n");
- return 0;
- }
-
- cm = (struct gsm48_service_request *) &gh->data[0];
- return cm->cm_service_type == GSM48_CMSERV_EMERGENCY;
-}
-
-struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- struct gsm48_hdr *gh;
- int8_t pdisc;
- uint8_t mtype;
- struct osmo_bsc_data *bsc;
- struct bsc_msc_data *msc, *pag_msc;
- struct bsc_subscr *subscr;
- int is_emerg = 0;
-
- bsc = conn->bts->network->bsc_data;
-
- if (msgb_l3len(msg) < sizeof(*gh)) {
- LOGP(DMSC, LOGL_ERROR, "There is no GSM48 header here.\n");
- return NULL;
- }
-
- gh = msgb_l3(msg);
- pdisc = gsm48_hdr_pdisc(gh);
- mtype = gsm48_hdr_msg_type(gh);
-
- /*
- * We are asked to select a MSC here but they are not equal. We
- * want to respond to a paging request on the MSC where we got the
- * request from. This is where we need to decide where this connection
- * will go.
- */
- if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP)
- goto paging;
- else if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) {
- is_emerg = is_cm_service_for_emerg(msg);
- goto round_robin;
- } else
- goto round_robin;
-
-round_robin:
- llist_for_each_entry(msc, &bsc->mscs, entry) {
- if (!msc->msc_con->is_authenticated)
- continue;
- if (!is_emerg && msc->type != MSC_CON_TYPE_NORMAL)
- continue;
- if (is_emerg && !msc->allow_emerg)
- continue;
-
- /* force round robin by moving it to the end */
- llist_move_tail(&msc->entry, &bsc->mscs);
- return msc;
- }
-
- return NULL;
-
-paging:
- subscr = extract_sub(conn, msg);
-
- if (!subscr) {
- LOGP(DMSC, LOGL_ERROR, "Got paged but no subscriber found.\n");
- return NULL;
- }
-
- pag_msc = paging_get_data(conn->bts, subscr);
- bsc_subscr_put(subscr);
-
- llist_for_each_entry(msc, &bsc->mscs, entry) {
- if (msc != pag_msc)
- continue;
-
- /*
- * We don't check if the MSC is connected. In case it
- * is not the connection will be dropped.
- */
-
- /* force round robin by moving it to the end */
- llist_move_tail(&msc->entry, &bsc->mscs);
- return msc;
- }
-
- LOGP(DMSC, LOGL_ERROR, "Got paged but no request found.\n");
- return NULL;
-}
-
-
-/**
- * This is used to scan a message for extra functionality of the BSC. This
- * includes scanning for location updating requests/acceptd and then send
- * a welcome USSD message to the subscriber.
- */
-int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- uint8_t pdisc = gsm48_hdr_pdisc(gh);
- uint8_t mtype = gsm48_hdr_msg_type(gh);
-
- if (pdisc == GSM48_PDISC_MM) {
- if (mtype == GSM48_MT_MM_LOC_UPD_REQUEST)
- handle_lu_request(conn, msg);
- } else if (pdisc == GSM48_PDISC_RR) {
- if (mtype == GSM48_MT_RR_PAG_RESP)
- handle_page_resp(conn, msg);
- }
-
- return 0;
-}
-
-static int send_welcome_ussd(struct gsm_subscriber_connection *conn)
-{
- struct osmo_bsc_sccp_con *bsc_con;
-
- bsc_con = conn->sccp_con;
- if (!bsc_con) {
- LOGP(DMSC, LOGL_DEBUG, "No SCCP connection associated.\n");
- return 0;
- }
-
- if (!bsc_con->msc->ussd_welcome_txt) {
- LOGP(DMSC, LOGL_DEBUG, "No USSD Welcome text defined.\n");
- return 0;
- }
-
- return BSS_SEND_USSD;
-}
-
-int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn)
-{
- bsc_send_ussd_notify(conn, 1, conn->sccp_con->msc->ussd_welcome_txt);
- bsc_send_ussd_release_complete(conn);
-
- return 0;
-}
-
-static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn,
- uint8_t *data, unsigned int length)
-{
- struct tlv_parsed tp;
- int parse_res;
- struct gsm_bts *bts = conn->bts;
- int tzunits;
- uint8_t tzbsd = 0;
- uint8_t dst = 0;
-
- parse_res = tlv_parse(&tp, &gsm48_mm_att_tlvdef, data, length, 0, 0);
- if (parse_res <= 0 && parse_res != -3)
- /* FIXME: -3 means unknown IE error, so this accepts messages
- * with unknown IEs. But parsing has aborted with the unknown
- * IE and the message is broken or parsed incompletely. */
- return 0;
-
- /* Is TZ patching enabled? */
- struct gsm_tz *tz = &bts->network->tz;
- if (!tz->override)
- return 0;
-
- /* Convert tz.hr and tz.mn to units */
- if (tz->hr < 0) {
- tzunits = -tz->hr*4;
- tzbsd |= 0x08;
- } else
- tzunits = tz->hr*4;
-
- tzunits = tzunits + (tz->mn/15);
-
- tzbsd |= (tzunits % 10)*0x10 + (tzunits / 10);
-
- /* Convert DST value */
- if (tz->dst >= 0 && tz->dst <= 2)
- dst = tz->dst;
-
- if (TLVP_PRESENT(&tp, GSM48_IE_UTC)) {
- LOGP(DMSC, LOGL_DEBUG,
- "Changing 'Local time zone' from 0x%02x to 0x%02x.\n",
- TLVP_VAL(&tp, GSM48_IE_UTC)[6], tzbsd);
- ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_UTC)))[0] = tzbsd;
- }
- if (TLVP_PRESENT(&tp, GSM48_IE_NET_TIME_TZ)) {
- LOGP(DMSC, LOGL_DEBUG,
- "Changing 'Universal time and local time zone' TZ from "
- "0x%02x to 0x%02x.\n",
- TLVP_VAL(&tp, GSM48_IE_NET_TIME_TZ)[6], tzbsd);
- ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_NET_TIME_TZ)))[6] = tzbsd;
- }
-#ifdef GSM48_IE_NET_DST
- if (TLVP_PRESENT(&tp, GSM48_IE_NET_DST)) {
- LOGP(DMSC, LOGL_DEBUG,
- "Changing 'Network daylight saving time' from "
- "0x%02x to 0x%02x.\n",
- TLVP_VAL(&tp, GSM48_IE_NET_DST)[0], dst);
- ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_NET_DST)))[0] = dst;
- }
-#endif
-
- return 0;
-}
-
-static int has_core_identity(struct bsc_msc_data *msc)
-{
- if (msc->core_mnc != -1)
- return 1;
- if (msc->core_mcc != -1)
- return 1;
- if (msc->core_lac != -1)
- return 1;
- if (msc->core_ci != -1)
- return 1;
- return 0;
-}
-
-/**
- * Messages coming back from the MSC.
- */
-int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
-{
- struct bsc_msc_data *msc;
- struct gsm_network *net;
- struct gsm48_loc_area_id *lai;
- struct gsm48_hdr *gh;
- uint8_t pdisc;
- uint8_t mtype;
- int length = msgb_l3len(msg);
-
- if (length < sizeof(*gh)) {
- LOGP(DMSC, LOGL_ERROR, "GSM48 header does not fit.\n");
- return -1;
- }
-
- gh = (struct gsm48_hdr *) msgb_l3(msg);
- length -= (const char *)&gh->data[0] - (const char *)gh;
-
- pdisc = gsm48_hdr_pdisc(gh);
- if (pdisc != GSM48_PDISC_MM)
- return 0;
-
- mtype = gsm48_hdr_msg_type(gh);
- net = conn->bts->network;
- msc = conn->sccp_con->msc;
-
- if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) {
- if (has_core_identity(msc)) {
- if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) {
- /* overwrite LAI in the message */
- lai = (struct gsm48_loc_area_id *) &gh->data[0];
- gsm48_generate_lai(lai, net->country_code,
- net->network_code,
- conn->bts->location_area_code);
- }
- }
-
- if (conn->sccp_con->new_subscriber)
- return send_welcome_ussd(conn);
- return 0;
- } else if (mtype == GSM48_MT_MM_INFO) {
- bsc_patch_mm_info(conn, &gh->data[0], length);
- }
-
- return 0;
-}
diff --git a/src/osmo-bsc/osmo_bsc_grace.c b/src/osmo-bsc/osmo_bsc_grace.c
deleted file mode 100644
index 63afa20d0..000000000
--- a/src/osmo-bsc/osmo_bsc_grace.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2013 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <openbsc/osmo_bsc_grace.h>
-#include <openbsc/osmo_bsc_rf.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/gsm_04_80.h>
-#include <openbsc/bsc_subscriber.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-
-int bsc_grace_allow_new_connection(struct gsm_network *network, struct gsm_bts *bts)
-{
- if (bts->excl_from_rf_lock)
- return 1;
- return network->bsc_data->rf_ctrl->policy == S_RF_ON;
-}
-
-
-static int normal_paging(struct bsc_subscr *subscr, int chan_needed,
- struct bsc_msc_data *msc)
-{
- /* we can't page by lac.. we need to page everything */
- if (msc->core_lac != -1) {
- struct gsm_bts *bts;
-
- llist_for_each_entry(bts, &msc->network->bts_list, list)
- paging_request_bts(bts, subscr, chan_needed, NULL, msc);
-
- return 0;
- }
-
- return paging_request(msc->network, subscr, chan_needed, NULL, msc);
-}
-
-static int locked_paging(struct bsc_subscr *subscr, int chan_needed,
- struct bsc_msc_data *msc)
-{
- struct gsm_bts *bts = NULL;
-
- /*
- * Check if there is any BTS that is on for the given lac. Start
- * with NULL and iterate through all bts.
- */
- llist_for_each_entry(bts, &msc->network->bts_list, list) {
- /*
- * continue if the BTS is not excluded from the lock
- */
- if (!bts->excl_from_rf_lock)
- continue;
-
- /* in case of no lac patching is in place, check the BTS */
- if (msc->core_lac == -1 && subscr->lac != bts->location_area_code)
- continue;
-
- /*
- * now page on this bts
- */
- paging_request_bts(bts, subscr, chan_needed, NULL, msc);
- };
-
- /* All bts are either off or in the grace period */
- return 0;
-}
-
-/**
- * Try to not page if everything the cell is not on.
- */
-int bsc_grace_paging_request(enum signal_rf rf_policy,
- struct bsc_subscr *subscr,
- int chan_needed,
- struct bsc_msc_data *msc)
-{
- if (rf_policy == S_RF_ON)
- return normal_paging(subscr, chan_needed, msc);
- return locked_paging(subscr, chan_needed, msc);
-}
-
-static int handle_sub(struct gsm_lchan *lchan, const char *text)
-{
- struct gsm_subscriber_connection *conn;
-
- /* only send it to TCH */
- if (lchan->type != GSM_LCHAN_TCH_H && lchan->type != GSM_LCHAN_TCH_F)
- return -1;
-
- /* only send on the primary channel */
- conn = lchan->conn;
- if (!conn)
- return -1;
-
- if (conn->lchan != lchan)
- return -1;
-
- /* only when active */
- if (lchan->state != LCHAN_S_ACTIVE)
- return -1;
-
- bsc_send_ussd_notify(conn, 0, text);
- bsc_send_ussd_release_complete(conn);
-
- return 0;
-}
-
-/*
- * The place to handle the grace mode. Right now we will send
- * USSD messages to the subscriber, in the future we might start
- * a timer to have different modes for the grace period.
- */
-static int handle_grace(struct gsm_network *network)
-{
- int ts_nr, lchan_nr;
- struct gsm_bts *bts;
- struct gsm_bts_trx *trx;
-
- if (!network->bsc_data->mid_call_txt)
- return 0;
-
- llist_for_each_entry(bts, &network->bts_list, list) {
- llist_for_each_entry(trx, &bts->trx_list, list) {
- for (ts_nr = 0; ts_nr < TRX_NR_TS; ++ts_nr) {
- struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
- for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; ++lchan_nr) {
- handle_sub(&ts->lchan[lchan_nr],
- network->bsc_data->mid_call_txt);
- }
- }
- }
- }
- return 0;
-}
-
-static int handle_rf_signal(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct rf_signal_data *sig;
-
- if (subsys != SS_RF)
- return -1;
-
- sig = signal_data;
-
- if (signal == S_RF_GRACE)
- handle_grace(sig->net);
-
- return 0;
-}
-
-static __attribute__((constructor)) void on_dso_load_grace(void)
-{
- osmo_signal_register_handler(SS_RF, handle_rf_signal, NULL);
-}
diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c
deleted file mode 100644
index cf188a9e0..000000000
--- a/src/osmo-bsc/osmo_bsc_main.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2011 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <openbsc/bss.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/osmo_bsc.h>
-#include <openbsc/osmo_bsc_rf.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/signal.h>
-#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>
-#include <osmocom/ctrl/ports.h>
-#include <osmocom/ctrl/control_vty.h>
-
-#include <osmocom/core/application.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/stats.h>
-#include <osmocom/gsm/protocol/gsm_12_21.h>
-
-#include <osmocom/abis/abis.h>
-
-#include <osmocom/sccp/sccp.h>
-
-#define _GNU_SOURCE
-#include <getopt.h>
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-
-#include "../../bscconfig.h"
-
-struct gsm_network *bsc_gsmnet = 0;
-static const char *config_file = "openbsc.cfg";
-static const char *rf_ctrl = NULL;
-extern const char *openbsc_copyright;
-static int daemonize = 0;
-static struct llist_head access_lists;
-
-struct llist_head *bsc_access_lists(void)
-{
- return &access_lists;
-}
-
-static void print_usage()
-{
- printf("Usage: osmo-bsc\n");
-}
-
-static void print_help()
-{
- printf(" Some useful help...\n");
- printf(" -h --help this text\n");
- printf(" -D --daemonize Fork the process into a background daemon\n");
- printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
- printf(" -s --disable-color\n");
- printf(" -T --timestamp. Print a timestamp in the debug output.\n");
- printf(" -c --config-file filename The config file to use.\n");
- printf(" -l --local=IP. The local address of the MGCP.\n");
- printf(" -e --log-level number. Set a global loglevel.\n");
- printf(" -r --rf-ctl NAME. A unix domain socket to listen for cmds.\n");
- printf(" -t --testmode. A special mode to provoke failures at the MSC.\n");
-}
-
-static void handle_options(int argc, char **argv)
-{
- while (1) {
- int option_index = 0, c;
- static struct option long_options[] = {
- {"help", 0, 0, 'h'},
- {"debug", 1, 0, 'd'},
- {"daemonize", 0, 0, 'D'},
- {"config-file", 1, 0, 'c'},
- {"disable-color", 0, 0, 's'},
- {"timestamp", 0, 0, 'T'},
- {"local", 1, 0, 'l'},
- {"log-level", 1, 0, 'e'},
- {"rf-ctl", 1, 0, 'r'},
- {"testmode", 0, 0, 't'},
- {0, 0, 0, 0}
- };
-
- c = getopt_long(argc, argv, "hd:DsTc:e:r:t",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- print_usage();
- print_help();
- exit(0);
- case 's':
- log_set_use_color(osmo_stderr_target, 0);
- break;
- case 'd':
- log_parse_category_mask(osmo_stderr_target, optarg);
- break;
- case 'D':
- daemonize = 1;
- break;
- case 'c':
- config_file = optarg;
- break;
- case 'T':
- log_set_print_timestamp(osmo_stderr_target, 1);
- break;
- case 'e':
- log_set_log_level(osmo_stderr_target, atoi(optarg));
- break;
- case 'r':
- rf_ctrl = optarg;
- break;
- default:
- /* ignore */
- break;
- }
- }
-}
-
-extern int bsc_vty_go_parent(struct vty *vty);
-
-static struct vty_app_info vty_info = {
- .name = "OsmoBSC",
- .version = PACKAGE_VERSION,
- .go_parent_cb = bsc_vty_go_parent,
- .is_config_node = bsc_vty_is_config_node,
-};
-
-extern int bsc_shutdown_net(struct gsm_network *net);
-static void signal_handler(int signal)
-{
- struct bsc_msc_data *msc;
-
- fprintf(stdout, "signal %u received\n", signal);
-
- switch (signal) {
- case SIGINT:
- case SIGTERM:
- bsc_shutdown_net(bsc_gsmnet);
- osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
- sleep(3);
- exit(0);
- break;
- case SIGABRT:
- /* in case of abort, we want to obtain a talloc report
- * and then return to the caller, who will abort the process */
- case SIGUSR1:
- talloc_report(tall_vty_ctx, stderr);
- talloc_report_full(tall_bsc_ctx, stderr);
- break;
- case SIGUSR2:
- if (!bsc_gsmnet->bsc_data)
- return;
- llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry)
- bsc_msc_lost(msc->msc_con);
- break;
- default:
- break;
- }
-}
-
-int main(int argc, char **argv)
-{
- struct bsc_msc_data *msc;
- struct osmo_bsc_data *data;
- int rc;
-
- tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
- msgb_talloc_ctx_init(tall_bsc_ctx, 0);
-
- /* Allocate global gsm_network struct */
- rc = bsc_network_alloc(NULL);
- if (rc) {
- fprintf(stderr, "Allocation failed. exiting.\n");
- exit(1);
- }
-
- osmo_init_logging(&log_info);
- osmo_stats_init(tall_bsc_ctx);
-
- bts_init();
- libosmo_abis_init(tall_bsc_ctx);
-
- /* enable filters */
-
- /* This needs to precede handle_options() */
- vty_info.copyright = openbsc_copyright;
- vty_init(&vty_info);
- bsc_vty_init(bsc_gsmnet);
- bsc_msg_lst_vty_init(tall_bsc_ctx, &access_lists, BSC_NODE);
- ctrl_vty_init(tall_bsc_ctx);
-
- /* Initalize SS7 */
- osmo_ss7_init();
- osmo_ss7_vty_init_asp(tall_bsc_ctx);
-
- INIT_LLIST_HEAD(&access_lists);
-
- /* parse options */
- handle_options(argc, argv);
-
- /* seed the PRNG */
- srand(time(NULL));
-
- /* initialize SCCP */
- sccp_set_log_area(DSCCP);
-
- /* Read the config */
- rc = bsc_network_configure(config_file);
- if (rc < 0) {
- fprintf(stderr, "Bootstrapping the network failed. exiting.\n");
- exit(1);
- }
- bsc_api_init(bsc_gsmnet, osmo_bsc_api());
-
- /* start control interface after reading config for
- * ctrl_vty_get_bind_addr() */
- bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet,
- ctrl_vty_get_bind_addr(),
- OSMO_CTRL_PORT_NITB_BSC);
- if (!bsc_gsmnet->ctrl) {
- fprintf(stderr, "Failed to init the control interface. Exiting.\n");
- exit(1);
- }
-
- rc = bsc_ctrl_cmds_install(bsc_gsmnet);
- if (rc < 0) {
- fprintf(stderr, "Failed to install control commands. Exiting.\n");
- exit(1);
- }
-
- data = bsc_gsmnet->bsc_data;
- if (rf_ctrl)
- osmo_talloc_replace_string(data, &data->rf_ctrl_name, rf_ctrl);
-
- data->rf_ctrl = osmo_bsc_rf_create(data->rf_ctrl_name, bsc_gsmnet);
- if (!data->rf_ctrl) {
- fprintf(stderr, "Failed to create the RF service.\n");
- exit(1);
- }
-
- llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry) {
- if (osmo_bsc_msc_init(msc) != 0) {
- LOGP(DNAT, LOGL_ERROR, "Failed to start up. Exiting.\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);
- }
-
- if (osmo_bsc_audio_init(bsc_gsmnet) != 0) {
- LOGP(DMSC, LOGL_ERROR, "Failed to register audio support.\n");
- exit(1);
- }
-
- signal(SIGINT, &signal_handler);
- signal(SIGTERM, &signal_handler);
- signal(SIGABRT, &signal_handler);
- signal(SIGUSR1, &signal_handler);
- signal(SIGUSR2, &signal_handler);
- osmo_init_ignore_signals();
-
- if (daemonize) {
- rc = osmo_daemonize();
- if (rc < 0) {
- perror("Error during daemonize");
- exit(1);
- }
- }
-
- while (1) {
- osmo_select_main(0);
- }
-
- return 0;
-}
diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c
deleted file mode 100644
index 351fd2ced..000000000
--- a/src/osmo-bsc/osmo_bsc_msc.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * Handle the connection to the MSC. This include ping/timeout/reconnect
- * (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2015 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <openbsc/bsc_nat.h>
-#include <osmocom/ctrl/control_cmd.h>
-#include <osmocom/ctrl/control_if.h>
-#include <osmocom/crypt/auth.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/signal.h>
-
-#include <osmocom/core/talloc.h>
-
-#include <osmocom/gsm/gsm0808.h>
-
-#include <osmocom/sccp/sccp.h>
-
-#include <osmocom/abis/ipa.h>
-
-#include <sys/socket.h>
-#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);
-static void send_ping(struct bsc_msc_data *data);
-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;
- struct msgb *mgcp;
- int ret;
-
- mgcp = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
- if (!mgcp) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
- return -1;
- }
-
- ret = read(fd->fd, mgcp->data, 4096 - 128);
- if (ret <= 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
- msgb_free(mgcp);
- return -1;
- } else if (ret > 4096 - 128) {
- LOGP(DMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
- msgb_free(mgcp);
- return -1;
- }
-
- mgcp->l2h = msgb_put(mgcp, ret);
- msc_queue_write(data->msc_con, mgcp, IPAC_PROTO_MGCP_OLD);
- return 0;
-}
-
-static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
-{
- int ret;
-
- LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
-
- ret = write(fd->fd, msg->data, msg->len);
- if (ret != msg->len)
- LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP GW (%s).\n", strerror(errno));
-
- return ret;
-}
-
-#if 0
-static void mgcp_forward(struct bsc_msc_data *data, struct msgb *msg)
-{
- struct msgb *mgcp;
-
- if (msgb_l2len(msg) > 4096) {
- LOGP(DMGCP, LOGL_ERROR, "Can not forward too big message.\n");
- return;
- }
-
- mgcp = msgb_alloc(4096, "mgcp_to_gw");
- if (!mgcp) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to send message.\n");
- return;
- }
-
- msgb_put(mgcp, msgb_l2len(msg));
- memcpy(mgcp->data, msg->l2h, mgcp->len);
- if (osmo_wqueue_enqueue(&data->mgcp_agent, mgcp) != 0) {
- LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW.\n");
- msgb_free(mgcp);
- }
-}
-#endif
-
-static int mgcp_create_port(struct bsc_msc_data *data)
-{
- int on;
- struct sockaddr_in addr;
-
- data->mgcp_agent.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (data->mgcp_agent.bfd.fd < 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
- return -1;
- }
-
- on = 1;
- setsockopt(data->mgcp_agent.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- /* try to bind the socket */
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr.sin_port = 0;
-
- if (bind(data->mgcp_agent.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to bind to any port.\n");
- close(data->mgcp_agent.bfd.fd);
- data->mgcp_agent.bfd.fd = -1;
- return -1;
- }
-
- /* connect to the remote */
- addr.sin_port = htons(2427);
- if (connect(data->mgcp_agent.bfd.fd, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to connect to local MGCP GW. %s\n", strerror(errno));
- close(data->mgcp_agent.bfd.fd);
- data->mgcp_agent.bfd.fd = -1;
- return -1;
- }
-
- osmo_wqueue_init(&data->mgcp_agent, 10);
- data->mgcp_agent.bfd.when = BSC_FD_READ;
- data->mgcp_agent.bfd.data = data;
- data->mgcp_agent.read_cb = mgcp_do_read;
- data->mgcp_agent.write_cb = mgcp_do_write;
-
- if (osmo_fd_register(&data->mgcp_agent.bfd) != 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
- close(data->mgcp_agent.bfd.fd);
- data->mgcp_agent.bfd.fd = -1;
- return -1;
- }
-
- return 0;
-}
-
-
-/*
- * Send data to the network
- */
-int msc_queue_write(struct bsc_msc_connection *conn, struct msgb *msg, int proto)
-{
- ipa_prepend_header(msg, proto);
- if (osmo_wqueue_enqueue(&conn->write_queue, msg) != 0) {
- LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto);
- msgb_free(msg);
- return -1;
- }
-
- return 0;
-}
-
-#if 0
-int msc_queue_write_with_ping(struct bsc_msc_connection *conn,
- struct msgb *msg, int proto)
-{
- struct bsc_msc_data *data;
- uint8_t val;
-
- /* prepend the header */
- ipa_prepend_header(msg, proto);
- if (osmo_wqueue_enqueue(&conn->write_queue, msg) != 0) {
- LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto);
- msgb_free(msg);
- return -1;
- }
-
- /* add the ping as the other message */
- val = IPAC_MSGT_PING;
- msgb_l16tv_put(msg, 1, IPAC_PROTO_IPACCESS, &val);
-
- data = (struct bsc_msc_data *) conn->write_queue.bfd.data;
- schedule_ping_pong(data);
- return 0;
-}
-
-static int msc_alink_do_write(struct osmo_fd *fd, struct msgb *msg)
-{
- int ret;
-
- LOGP(DMSC, LOGL_DEBUG, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
- LOGP(DLMI, LOGL_DEBUG, "MSC TX %s\n", osmo_hexdump(msg->data, msg->len));
-
- ret = write(fd->fd, msg->data, msg->len);
- if (ret < msg->len)
- perror("MSC: Failed to send SCCP");
-
- return ret;
-}
-
-static void handle_ctrl(struct bsc_msc_data *msc, struct msgb *msg)
-{
- int ret;
- struct ctrl_cmd *cmd;
-
- cmd = ctrl_cmd_parse(msc->msc_con, msg);
- if (!cmd) {
- LOGP(DMSC, LOGL_ERROR, "Failed to parse control message.\n");
- cmd = talloc_zero(msc->msc_con, struct ctrl_cmd);
- if (!cmd) {
- LOGP(DMSC, LOGL_ERROR, "OOM!\n");
- return;
- }
- cmd->type = CTRL_TYPE_ERROR;
- cmd->id = "err";
- cmd->reply = "Failed to parse control message.";
-
- ctrl_cmd_send(&msc->msc_con->write_queue, cmd);
- talloc_free(cmd);
-
- return;
- }
-
- ret = ctrl_cmd_handle(msc->network->ctrl, cmd, msc->network);
- if (ret != CTRL_CMD_HANDLED)
- ctrl_cmd_send(&msc->msc_con->write_queue, cmd);
- talloc_free(cmd);
-}
-
-static void osmo_ext_handle(struct bsc_msc_data *msc, struct msgb *msg)
-{
- struct ipaccess_head *hh;
- struct ipaccess_head_ext *hh_ext;
-
- hh = (struct ipaccess_head *) msg->data;
- hh_ext = (struct ipaccess_head_ext *) hh->data;
- if (msg->len < sizeof(*hh) + sizeof(*hh_ext)) {
- LOGP(DMSC, LOGL_ERROR, "Packet too short for extended header.\n");
- return;
- }
-
- msg->l2h = hh_ext->data;
- if (hh_ext->proto == IPAC_PROTO_EXT_MGCP)
- mgcp_forward(msc, msg);
- else if (hh_ext->proto == IPAC_PROTO_EXT_LAC)
- send_lacs(msc->network, msc->msc_con);
- else if (hh_ext->proto == IPAC_PROTO_EXT_CTRL)
- handle_ctrl(msc, msg);
-}
-
-static int ipaccess_a_fd_cb(struct osmo_fd *bfd)
-{
- struct msgb *msg = NULL;
- struct ipaccess_head *hh;
- struct bsc_msc_data *data = (struct bsc_msc_data *) bfd->data;
- int ret;
-
- ret = ipa_msg_recv_buffered(bfd->fd, &msg, &data->msc_con->pending_msg);
- if (ret <= 0) {
- if (ret == -EAGAIN)
- return 0;
- if (ret == 0) {
- LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n");
- bsc_msc_lost(data->msc_con);
- return -1;
- }
-
- LOGP(DMSC, LOGL_ERROR, "Failed to parse ip access message: %d\n", ret);
- return -1;
- }
-
- LOGP(DLMI, LOGL_DEBUG, "From MSC: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]);
-
- /* handle base message handling */
- hh = (struct ipaccess_head *) msg->data;
-
- /* initialize the networking. This includes sending a GSM08.08 message */
- msg->cb[0] = (unsigned long) data;
- if (hh->proto == IPAC_PROTO_IPACCESS) {
- ipa_ccm_rcvmsg_base(msg, bfd);
- if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
- initialize_if_needed(data->msc_con);
- else if (msg->l2h[0] == IPAC_MSGT_ID_GET) {
- send_id_get_response(data, bfd->fd, msg);
- } else if (msg->l2h[0] == IPAC_MSGT_PONG) {
- osmo_timer_del(&data->pong_timer);
- }
- } else if (hh->proto == IPAC_PROTO_SCCP) {
- sccp_system_incoming_ctx(msg, data->msc_con);
- } else if (hh->proto == IPAC_PROTO_MGCP_OLD) {
- mgcp_forward(data, msg);
- } else if (hh->proto == IPAC_PROTO_OSMO) {
- osmo_ext_handle(data, msg);
- }
-
- msgb_free(msg);
- return 0;
-}
-
-static void send_ping(struct bsc_msc_data *data)
-{
- struct msgb *msg;
-
- msg = msgb_alloc_headroom(4096, 128, "ping");
- if (!msg) {
- LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n");
- return;
- }
-
- msg->l2h = msgb_put(msg, 1);
- msg->l2h[0] = IPAC_MSGT_PING;
-
- msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS);
-}
-
-static void schedule_ping_pong(struct bsc_msc_data *data)
-{
- /* send another ping in 20 seconds */
- osmo_timer_schedule(&data->ping_timer, data->ping_timeout, 0);
-
- /* also start a pong timer */
- osmo_timer_schedule(&data->pong_timer, data->pong_timeout, 0);
-}
-
-static void msc_ping_timeout_cb(void *_data)
-{
- struct bsc_msc_data *data = (struct bsc_msc_data *) _data;
- if (data->ping_timeout <= 0)
- return;
-
- send_ping(data);
- schedule_ping_pong(data);
-}
-
-static void msc_pong_timeout_cb(void *_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);
-}
-
-static void msc_connection_connected(struct bsc_msc_connection *con)
-{
- struct msc_signal_data sig;
- 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));
-
-// 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);
-}
-
-/*
- * The connection to the MSC was lost and we will need to free all
- * resources and then attempt to reconnect.
- */
-static void msc_connection_was_lost(struct bsc_msc_connection *msc)
-{
-// 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);
-
- msc->is_authenticated = 0;
-// bsc_msc_schedule_connect(msc);
-}
-
-static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn)
-{
- struct ipac_ext_lac_cmd *lac;
- struct gsm_bts *bts;
- struct msgb *msg;
- int lacs = 0;
-
- if (llist_empty(&net->bts_list)) {
- LOGP(DMSC, LOGL_ERROR, "No BTSs configured. Not sending LACs.\n");
- return;
- }
-
- msg = msgb_alloc_headroom(4096, 128, "LAC Command");
- if (!msg) {
- LOGP(DMSC, LOGL_ERROR, "Failed to create the LAC command.\n");
- return;
- }
-
- lac = (struct ipac_ext_lac_cmd *) msgb_put(msg, sizeof(*lac));
- lac->add_remove = 1;
-
- llist_for_each_entry(bts, &net->bts_list, list) {
- if (lacs++ == 0)
- lac->lac = htons(bts->location_area_code);
- else
- msgb_put_u16(msg, htons(bts->location_area_code));
- }
-
- lac->nr_extra_lacs = lacs - 1;
- ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_LAC);
- msc_queue_write(conn, msg, IPAC_PROTO_OSMO);
-}
-
-static void initialize_if_needed(struct bsc_msc_connection *conn)
-{
- struct msgb *msg;
-
- if (!conn->is_authenticated) {
- /* send a gsm 08.08 reset message from here */
- msg = gsm0808_create_reset();
- if (!msg) {
- LOGP(DMSC, LOGL_ERROR, "Failed to create the reset message.\n");
- return;
- }
-
- sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0, conn);
- msgb_free(msg);
- conn->is_authenticated = 1;
- }
-}
-
-static int answer_challenge(struct bsc_msc_data *data, struct msgb *inp, struct osmo_auth_vector *vec)
-{
- int ret;
- struct tlv_parsed tvp;
- const uint8_t *mrand;
- uint8_t mrand_len;
- struct osmo_sub_auth_data auth = {
- .type = OSMO_AUTH_TYPE_GSM,
- .algo = OSMO_AUTH_ALG_MILENAGE,
- };
-
- ret = ipa_ccm_idtag_parse_off(&tvp,
- inp->l2h + 1,
- msgb_l2len(inp) - 1, 1);
- if (ret < 0) {
- LOGP(DMSC, LOGL_ERROR, "ignoring IPA response "
- "message with malformed TLVs: %s\n", osmo_hexdump(inp->l2h + 1,
- msgb_l2len(inp) - 1));
- return 0;
- }
-
- mrand = TLVP_VAL(&tvp, 0x23);
- mrand_len = TLVP_LEN(&tvp, 0x23);
- if (mrand_len != 16) {
- LOGP(DMSC, LOGL_ERROR,
- "RAND is not 16 bytes. Was %d\n",
- mrand_len);
- return 0;
- }
-
- /* copy the key */
- memcpy(auth.u.umts.opc, data->bsc_key, 16);
- memcpy(auth.u.umts.k, data->bsc_key, 16);
- memset(auth.u.umts.amf, 0, 2);
- auth.u.umts.sqn = 0;
-
- /* generate the result */
- memset(vec, 0, sizeof(*vec));
- osmo_auth_gen_vec(vec, &auth, mrand);
- return 1;
-}
-
-
-static void send_id_get_response(struct bsc_msc_data *data, int fd, struct msgb *inp)
-{
- struct msc_signal_data sig;
- struct msgb *msg;
- struct osmo_auth_vector vec;
- int valid = 0;
-
- if (data->bsc_key_present)
- valid = answer_challenge(data, inp, &vec);
-
- msg = bsc_msc_id_get_resp(valid, data->bsc_token,
- vec.res, valid ? vec.res_len : 0);
- if (!msg)
- return;
- msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS);
-
- sig.data = data;
- 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)
- return -1;
-
- data->msc_con = bsc_msc_create(data, &data->dests);
- if (!data->msc_con) {
- LOGP(DMSC, LOGL_ERROR, "Creating the MSC network connection failed.\n");
- return -1;
- }
-
-// 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->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;
-
- llist_for_each_entry(msc_data, &net->bsc_data->mscs, entry)
- if (msc_data->nr == nr)
- return msc_data;
- return NULL;
-}
-
-struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr)
-{
- struct bsc_msc_data *msc_data;
-
- /* check if there is already one */
- msc_data = osmo_msc_data_find(net, nr);
- if (msc_data)
- return msc_data;
-
- msc_data = talloc_zero(net, struct bsc_msc_data);
- if (!msc_data)
- return NULL;
-
- llist_add_tail(&msc_data->entry, &net->bsc_data->mscs);
-
- /* Init back pointer */
- msc_data->network = net;
-
- INIT_LLIST_HEAD(&msc_data->dests);
- msc_data->ping_timeout = 20;
- msc_data->pong_timeout = 5;
- msc_data->core_mnc = -1;
- msc_data->core_mcc = -1;
- msc_data->core_ci = -1;
- msc_data->core_lac = -1;
- msc_data->rtp_base = 4000;
-
- msc_data->nr = nr;
- msc_data->allow_emerg = 1;
-
- /* Defaults for the audio setup */
- msc_data->amr_conf.m5_90 = 1;
-
- return msc_data;
-}
-
diff --git a/src/osmo-bsc/osmo_bsc_reset.c b/src/osmo-bsc/osmo_bsc_reset.c
deleted file mode 100644
index 0baf08089..000000000
--- a/src/osmo-bsc/osmo_bsc_reset.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/* (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;
-}
diff --git a/src/osmo-bsc/osmo_bsc_sigtran.c b/src/osmo-bsc/osmo_bsc_sigtran.c
deleted file mode 100644
index 0f6ca334f..000000000
--- a/src/osmo-bsc/osmo_bsc_sigtran.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/* (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>
-#include <openbsc/a_reset.h>
-#include <openbsc/gsm_04_80.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
-#define CS7_POINTCODE_DEFAULT_OFFSET 2
-
-/* Internal list with connections we currently maintain. This
- * list is of type struct osmo_bsc_sccp_con */
-static LLIST_HEAD(active_connections);
-
-/* The SCCP stack will not assign connection IDs to us automatically, we
- * will do this ourselves using a counter variable, that counts one up
- * for every new connection */
-static uint32_t conn_id_counter;
-
-/* 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(const struct bsc_msc_data *msc)
-{
- int conn_id = 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) {
- conn_id_counter = conn_id;
- return conn_id;
- }
- }
-
- return -1;
-}
-
-/* Send reset to MSC */
-static void osmo_bsc_sigtran_tx_reset(const struct bsc_msc_data *msc)
-{
- struct osmo_ss7_instance *ss7;
- struct msgb *msg;
-
- ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
- OSMO_ASSERT(ss7);
- LOGP(DMSC, LOGL_NOTICE, "Sending RESET to MSC: %s\n", osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
- msg = gsm0808_create_reset();
- osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr,
- &msc->a.msc_addr, msg);
-}
-
-/* Send reset-ack to MSC */
-void osmo_bsc_sigtran_tx_reset_ack(const struct bsc_msc_data *msc)
-{
- struct osmo_ss7_instance *ss7;
- struct msgb *msg;
- OSMO_ASSERT(msc);
-
- ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
- OSMO_ASSERT(ss7);
- LOGP(DMSC, LOGL_NOTICE, "Sending RESET ACK to MSC: %s\n", osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
- msg = gsm0808_create_reset_ack();
- osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr,
- &msc->a.msc_addr, msg);
-}
-
-/* Find an MSC by its sigtran point code */
-static struct bsc_msc_data *get_msc_by_addr(const struct osmo_sccp_addr *msc_addr)
-{
- struct osmo_ss7_instance *ss7;
- struct bsc_msc_data *msc;
- llist_for_each_entry(msc, msc_list, entry) {
- if (memcmp(msc_addr, &msc->a.msc_addr, sizeof(*msc_addr)) == 0)
- return msc;
- }
-
- ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
- OSMO_ASSERT(ss7);
- LOGP(DMSC, LOGL_ERROR, "Unable to find MSC data under address: %s\n", osmo_sccp_addr_name(ss7, msc_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_dt(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(const struct osmo_sccp_addr *msc_addr, struct msgb *msg,
- const struct osmo_sccp_user *scu)
-{
- struct osmo_ss7_instance *ss7;
- struct bsc_msc_data *msc = get_msc_by_addr(msc_addr);
- int rc = -EINVAL;
-
- if (msc) {
- msg->l3h = msgb_l2(msg);
- rc = bsc_handle_udt(msc, msg, msgb_l2len(msg));
- } else {
- ss7 = osmo_sccp_get_ss7(osmo_sccp_get_sccp(scu));
- OSMO_ASSERT(ss7);
- LOGP(DMSC, LOGL_NOTICE, "incoming unitdata data from unknown remote address: %s\n",
- osmo_sccp_addr_name(ss7, msc_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;
- struct osmo_bsc_sccp_con *bsc_con;
- 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, scu);
- 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)));
-
- /* 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)
- a_reset_conn_success(bsc_con->msc->a.reset);
-
- 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, 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, 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)
- a_reset_conn_fail(bsc_con->msc->a.reset);
-
- rc = osmo_bsc_sigtran_del_conn(bsc_con);
- }
- 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_ss7_instance *ss7;
- struct osmo_bsc_sccp_con *bsc_con;
- int conn_id;
-
- OSMO_ASSERT(conn);
- OSMO_ASSERT(msc);
-
- ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
- OSMO_ASSERT(ss7);
- LOGP(DMSC, LOGL_NOTICE, "Initializing resources for new SIGTRAN connection to MSC: %s...\n",
- osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
-
- if (a_reset_conn_ready(msc->a.reset) == false) {
- LOGP(DMSC, LOGL_ERROR, "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(const struct osmo_bsc_sccp_con *conn, struct msgb *msg)
-{
- struct osmo_ss7_instance *ss7;
- struct bsc_msc_data *msc;
- int conn_id;
- int rc;
-
- OSMO_ASSERT(conn);
- OSMO_ASSERT(msg);
- OSMO_ASSERT(conn->msc);
-
- msc = conn->msc;
-
- if (a_reset_conn_ready(msc->a.reset) == false) {
- LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
- return -EINVAL;
- }
-
- conn_id = conn->conn_id;
- ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
- OSMO_ASSERT(ss7);
- LOGP(DMSC, LOGL_NOTICE, "Opening new SIGTRAN connection (id=%i) to MSC: %s\n", conn_id,
- osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
-
- rc = osmo_sccp_tx_conn_req_msg(msc->a.sccp_user, conn_id, &msc->a.bsc_addr,
- &msc->a.msc_addr, msg);
-
- return rc;
-}
-
-/* Send data to MSC */
-int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg)
-{
- struct osmo_ss7_instance *ss7;
- int conn_id;
- int rc;
- struct bsc_msc_data *msc;
-
- OSMO_ASSERT(conn);
- OSMO_ASSERT(msg);
- OSMO_ASSERT(conn->msc);
-
- msc = conn->msc;
-
- if (a_reset_conn_ready(msc->a.reset) == false) {
- LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
- return -EINVAL;
- }
-
- conn_id = conn->conn_id;
-
- ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
- OSMO_ASSERT(ss7);
- LOGP(DMSC, LOGL_DEBUG, "Sending connection (id=%i) oriented data to MSC: %si\n",
- conn_id, osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
-
- rc = osmo_sccp_tx_data_msg(msc->a.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 *conn)
-{
- if (!conn)
- return 0;
-
- 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;
-
- /* This bahaviour might be caused by a bad connection. Maybe we
- * will have to go through the reset procedure again */
- a_reset_conn_fail(conn->msc->a.reset);
- }
-
- llist_del(&conn->entry);
- talloc_free(conn);
-
- return 0;
-}
-
-/* Send an USSD notification in case we loose the connection to the MSC */
-static void bsc_notify_msc_lost(const struct osmo_bsc_sccp_con *conn)
-{
- struct gsm_subscriber_connection *subscr_conn;
-
- /* Check if sccp conn is still present */
- if (!conn)
- return;
- subscr_conn = conn->conn;
-
- /* send USSD notification if string configured and conn->data is set */
- if (!subscr_conn)
- return;
-
- /* check for config string */
- if (!conn->msc->ussd_msc_lost_txt)
- return;
- if (conn->msc->ussd_msc_lost_txt[0] == '\0')
- return;
-
- /* send USSD notification */
- bsc_send_ussd_notify(subscr_conn, 1, subscr_conn->sccp_con->msc->ussd_msc_lost_txt);
- bsc_send_ussd_release_complete(subscr_conn);
-}
-
-/* Close all open sigtran connections and channels */
-void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc)
-{
- struct osmo_bsc_sccp_con *conn;
- struct osmo_bsc_sccp_con *conn_temp;
- OSMO_ASSERT(msc);
-
- /* Close all open connections */
- llist_for_each_entry_safe(conn, conn_temp, &active_connections, entry) {
-
- /* We only may close connections which actually belong to this
- * MSC. All other open connections are left untouched */
- if (conn->msc == msc) {
- /* Notify active connection users via USSD that the MSC is down */
- bsc_notify_msc_lost(conn);
-
- /* Take down all occopied RF channels */
- if (conn->conn)
- gsm0808_clear(conn->conn);
-
- /* Disconnect all Sigtran connections */
- osmo_sccp_tx_disconn(msc->a.sccp_user, conn->conn_id, &msc->a.bsc_addr, 0);
-
- /* Delete subscriber connection */
- osmo_bsc_sigtran_del_conn(conn);
- }
- }
-}
-
-/* Callback function: Close all open connections */
-static void osmo_bsc_sigtran_reset_cb(const void *priv)
-{
- struct bsc_msc_data *msc = (struct bsc_msc_data*) priv;
-
- /* Shut down all ongoing traffic */
- osmo_bsc_sigtran_reset(msc);
-
- /* Send reset to MSC */
- osmo_bsc_sigtran_tx_reset(msc);
-}
-
-/* Default point-code to be used as local address (BSC) */
-#define BSC_DEFAULT_PC "0.23.3"
-
-/* Default point-code to be used as remote address (MSC) */
-#define MSC_DEFAULT_PC "0.23.1"
-
-/* Initalize osmo sigtran backhaul */
-int osmo_bsc_sigtran_init(struct llist_head *mscs)
-{
- bool free_attempt_used = false;
- bool fail_on_next_invalid_cfg = false;
-
- struct bsc_msc_data *msc;
- char msc_name[32];
- uint32_t default_pc;
-
- OSMO_ASSERT(mscs);
- msc_list = mscs;
-
- llist_for_each_entry(msc, msc_list, entry) {
- snprintf(msc_name, sizeof(msc_name), "msc-%u", msc->nr);
- LOGP(DMSC, LOGL_NOTICE, "Initializing SCCP connection to MSC %s\n", msc_name);
-
- /* Check if the VTY could determine a valid CS7 instance,
- * use safe default in case none is set */
- if (msc->a.cs7_instance_valid == false) {
- msc->a.cs7_instance = 0;
- if (fail_on_next_invalid_cfg)
- goto fail_auto_cofiguration;
- free_attempt_used = true;
- }
- LOGP(DMSC, LOGL_NOTICE, "CS7 Instance identifier, A-Interface: %u\n", msc->a.cs7_instance);
-
- /* Pre-Check if there is an ss7 instance present */
- if (osmo_ss7_instance_find(msc->a.cs7_instance) == NULL) {
- if (fail_on_next_invalid_cfg)
- goto fail_auto_cofiguration;
- free_attempt_used = true;
- }
-
- /* SS7 Protocol stack */
- default_pc = osmo_ss7_pointcode_parse(NULL, BSC_DEFAULT_PC);
- msc->a.sccp =
- osmo_sccp_simple_client_on_ss7_id(msc, msc->a.cs7_instance, msc_name, default_pc,
- OSMO_SS7_ASP_PROT_M3UA, 0, NULL, 0, NULL);
- if (!msc->a.sccp)
- return -EINVAL;
-
- /* Check if the sccp-address fullfills minimum requirements (SSN+PC is present,
- * automatically recover addresses if the addresses are not set up properly) */
- if (!osmo_sccp_check_addr(&msc->a.bsc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
- if (fail_on_next_invalid_cfg)
- goto fail_auto_cofiguration;
- free_attempt_used = true;
-
- LOGP(DMSC, LOGL_NOTICE,
- "A-interface: invalid or missing local (BSC) SCCP address (a.bsc_addr=%s)\n",
- osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
- osmo_sccp_local_addr_by_instance(&msc->a.bsc_addr, msc->a.sccp, SCCP_SSN_BSSAP);
- LOGP(DMSC, LOGL_NOTICE,
- "A-interface: using automatically generated local (BSC) SCCP address (a.bsc_addr=%s)\n",
- osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
- } else {
- LOGP(DMSC, LOGL_NOTICE,
- "A-interface: using local (BSC) automatically SCCP address (a.msc_addr=%s)\n",
- osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
- }
-
- if (!osmo_sccp_check_addr(&msc->a.msc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
- if (fail_on_next_invalid_cfg)
- goto fail_auto_cofiguration;
- free_attempt_used = true;
-
- LOGP(DMSC, LOGL_NOTICE,
- "A-interface: invalid or missing remote (MSC) SCCP address for the MSC (a.msc_addr=%s)\n",
- osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
- osmo_sccp_local_addr_by_instance(&msc->a.msc_addr, msc->a.sccp, SCCP_SSN_BSSAP);
- msc->a.msc_addr.pc = osmo_ss7_pointcode_parse(NULL, MSC_DEFAULT_PC);
- LOGP(DMSC, LOGL_NOTICE,
- "A-interface: using automatically generated remote (MSC) SCCP address (a.msc_addr=%s)\n",
- osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
- free_attempt_used = true;
- } else {
- LOGP(DMSC, LOGL_NOTICE,
- "A-interface: using remote (MSC) automatically SCCP address (a.msc_addr=%s)\n",
- osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
- }
-
- /* Bind SCCP user */
- msc->a.sccp_user = osmo_sccp_user_bind(msc->a.sccp, msc_name, sccp_sap_up, msc->a.bsc_addr.ssn);
- if (!msc->a.sccp_user)
- return -EINVAL;
-
- /* Start MSC-Reset procedure */
- msc->a.reset = a_reset_alloc(msc, msc_name, osmo_bsc_sigtran_reset_cb, msc);
- if (!msc->a.reset)
- return -EINVAL;
-
- /* If we have detected that the SS7 configuration of the MSC we have just initalized
- * was incomplete or completely missing, we can not tolerate another incomplete
- * configuration. The reson for this is that we do only specify exactly one default
- * pointcode pair. We also specify localhost as default IP-Address. If we have wanted
- * to support multiple MSCs with automatic configuration we would be forced to invent
- * a complex ruleset how to allocate the pointcodes and respective IP-Addresses.
- * Furthermore, the situation where a single BSC is connected to multiple MSCs
- * is a very rare situation anyway. In this case we expect the user to experienced
- * enough to create a valid SS7/CS7 VTY configuration that does not lack any
- * components */
- if (free_attempt_used)
- fail_on_next_invalid_cfg = true;
- }
-
- return 0;
-
-fail_auto_cofiguration:
- LOGP(DMSC, LOGL_ERROR,
- "A-interface: More than one invalid/inclomplete configuration detected, unable to revover - check config file!\n");
- return -EINVAL;
-}
diff --git a/src/osmo-bsc/osmo_bsc_vty.c b/src/osmo-bsc/osmo_bsc_vty.c
deleted file mode 100644
index 8edcbf390..000000000
--- a/src/osmo-bsc/osmo_bsc_vty.c
+++ /dev/null
@@ -1,1039 +0,0 @@
-/* Osmo BSC VTY Configuration */
-/* (C) 2009-2015 by Holger Hans Peter Freyther
- * (C) 2009-2014 by On-Waves
- * 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/licenses/>.
- *
- */
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/osmo_bsc.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/vty.h>
-#include <openbsc/bsc_subscriber.h>
-#include <openbsc/debug.h>
-#include <openbsc/bsc_msg_filter.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/sccp/sccp_types.h>
-
-#include <time.h>
-
-
-#define IPA_STR "IP.ACCESS specific\n"
-
-extern struct gsm_network *bsc_gsmnet;
-
-static struct osmo_bsc_data *osmo_bsc_data(struct vty *vty)
-{
- return bsc_gsmnet->bsc_data;
-}
-
-static struct bsc_msc_data *bsc_msc_data(struct vty *vty)
-{
- return vty->index;
-}
-
-static struct cmd_node bsc_node = {
- BSC_NODE,
- "%s(config-bsc)# ",
- 1,
-};
-
-static struct cmd_node msc_node = {
- MSC_NODE,
- "%s(config-msc)# ",
- 1,
-};
-
-DEFUN(cfg_net_msc, cfg_net_msc_cmd,
- "msc [<0-1000>]", "Configure MSC details\n" "MSC connection to configure\n")
-{
- int index = argc == 1 ? atoi(argv[0]) : 0;
- struct bsc_msc_data *msc;
-
- msc = osmo_msc_data_alloc(bsc_gsmnet, index);
- if (!msc) {
- vty_out(vty, "%%Failed to allocate MSC data.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty->index = msc;
- vty->node = MSC_NODE;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc, cfg_net_bsc_cmd,
- "bsc", "Configure BSC\n")
-{
- vty->node = BSC_NODE;
- return CMD_SUCCESS;
-}
-
-static void write_msc_amr_options(struct vty *vty, struct bsc_msc_data *msc)
-{
-#define WRITE_AMR(vty, msc, name, var) \
- vty_out(vty, " amr-config %s %s%s", \
- name, msc->amr_conf.var ? "allowed" : "forbidden", \
- VTY_NEWLINE);
-
- WRITE_AMR(vty, msc, "12_2k", m12_2);
- WRITE_AMR(vty, msc, "10_2k", m10_2);
- WRITE_AMR(vty, msc, "7_95k", m7_95);
- WRITE_AMR(vty, msc, "7_40k", m7_40);
- WRITE_AMR(vty, msc, "6_70k", m6_70);
- WRITE_AMR(vty, msc, "5_90k", m5_90);
- WRITE_AMR(vty, msc, "5_15k", m5_15);
- WRITE_AMR(vty, msc, "4_75k", m4_75);
-#undef WRITE_AMR
-}
-
-static void write_msc(struct vty *vty, struct bsc_msc_data *msc)
-{
- struct bsc_msc_dest *dest;
-
- vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE);
- if (msc->bsc_token)
- vty_out(vty, " token %s%s", msc->bsc_token, VTY_NEWLINE);
- if (msc->bsc_key_present)
- vty_out(vty, " auth-key %s%s",
- osmo_hexdump(msc->bsc_key, sizeof(msc->bsc_key)), VTY_NEWLINE);
- if (msc->core_mnc != -1)
- vty_out(vty, " core-mobile-network-code %d%s",
- msc->core_mnc, VTY_NEWLINE);
- if (msc->core_mcc != -1)
- vty_out(vty, " core-mobile-country-code %d%s",
- msc->core_mcc, VTY_NEWLINE);
- if (msc->core_lac != -1)
- vty_out(vty, " core-location-area-code %d%s",
- msc->core_lac, VTY_NEWLINE);
- if (msc->core_ci != -1)
- vty_out(vty, " core-cell-identity %d%s",
- msc->core_ci, VTY_NEWLINE);
- vty_out(vty, " ip.access rtp-base %d%s", msc->rtp_base, VTY_NEWLINE);
-
- if (msc->ping_timeout == -1)
- vty_out(vty, " no timeout-ping%s", VTY_NEWLINE);
- else {
- vty_out(vty, " timeout-ping %d%s", msc->ping_timeout, VTY_NEWLINE);
- vty_out(vty, " timeout-pong %d%s", msc->pong_timeout, VTY_NEWLINE);
- if (msc->advanced_ping)
- vty_out(vty, " timeout-ping advanced%s", VTY_NEWLINE);
- else
- vty_out(vty, " no timeout-ping advanced%s", VTY_NEWLINE);
- }
-
- if (msc->ussd_welcome_txt)
- vty_out(vty, " bsc-welcome-text %s%s", msc->ussd_welcome_txt, VTY_NEWLINE);
- else
- vty_out(vty, " no bsc-welcome-text%s", VTY_NEWLINE);
-
- if (msc->ussd_msc_lost_txt && msc->ussd_msc_lost_txt[0])
- vty_out(vty, " bsc-msc-lost-text %s%s", msc->ussd_msc_lost_txt, VTY_NEWLINE);
- else
- vty_out(vty, " no bsc-msc-lost-text%s", VTY_NEWLINE);
-
- if (msc->ussd_grace_txt && msc->ussd_grace_txt[0])
- vty_out(vty, " bsc-grace-text %s%s", msc->ussd_grace_txt, VTY_NEWLINE);
- else
- vty_out(vty, " no bsc-grace-text%s", VTY_NEWLINE);
-
- if (msc->audio_length != 0) {
- int i;
-
- vty_out(vty, " codec-list ");
- for (i = 0; i < msc->audio_length; ++i) {
- if (i != 0)
- vty_out(vty, " ");
-
- if (msc->audio_support[i]->hr)
- vty_out(vty, "hr%.1u", msc->audio_support[i]->ver);
- else
- vty_out(vty, "fr%.1u", msc->audio_support[i]->ver);
- }
- vty_out(vty, "%s", VTY_NEWLINE);
-
- }
-
- llist_for_each_entry(dest, &msc->dests, list)
- vty_out(vty, " dest %s %d %d%s", dest->ip, dest->port,
- dest->dscp, VTY_NEWLINE);
-
- vty_out(vty, " type %s%s", msc->type == MSC_CON_TYPE_NORMAL ?
- "normal" : "local", VTY_NEWLINE);
- vty_out(vty, " allow-emergency %s%s", msc->allow_emerg ?
- "allow" : "deny", VTY_NEWLINE);
-
- if (msc->local_pref)
- vty_out(vty, " local-prefix %s%s", msc->local_pref, VTY_NEWLINE);
-
- if (msc->acc_lst_name)
- vty_out(vty, " access-list-name %s%s", msc->acc_lst_name, VTY_NEWLINE);
-
- /* write amr options */
- write_msc_amr_options(vty, msc);
-
- /* write sccp connection configuration */
- if (msc->a.bsc_addr_name) {
- vty_out(vty, " bsc-addr %s%s",
- msc->a.bsc_addr_name, VTY_NEWLINE);
- }
- if (msc->a.msc_addr_name) {
- vty_out(vty, " msc-addr %s%s",
- msc->a.msc_addr_name, VTY_NEWLINE);
- }
-}
-
-static int config_write_msc(struct vty *vty)
-{
- struct bsc_msc_data *msc;
- struct osmo_bsc_data *bsc = osmo_bsc_data(vty);
-
- llist_for_each_entry(msc, &bsc->mscs, entry)
- write_msc(vty, msc);
-
- return CMD_SUCCESS;
-}
-
-static int config_write_bsc(struct vty *vty)
-{
- struct osmo_bsc_data *bsc = osmo_bsc_data(vty);
-
- vty_out(vty, "bsc%s", VTY_NEWLINE);
- if (bsc->mid_call_txt)
- vty_out(vty, " mid-call-text %s%s", bsc->mid_call_txt, VTY_NEWLINE);
- vty_out(vty, " mid-call-timeout %d%s", bsc->mid_call_timeout, VTY_NEWLINE);
- if (bsc->rf_ctrl_name)
- vty_out(vty, " bsc-rf-socket %s%s",
- bsc->rf_ctrl_name, VTY_NEWLINE);
-
- if (bsc->auto_off_timeout != -1)
- vty_out(vty, " bsc-auto-rf-off %d%s",
- bsc->auto_off_timeout, VTY_NEWLINE);
-
- if (bsc->ussd_no_msc_txt && bsc->ussd_no_msc_txt[0])
- vty_out(vty, " missing-msc-text %s%s", bsc->ussd_no_msc_txt, VTY_NEWLINE);
- else
- vty_out(vty, " no missing-msc-text%s", VTY_NEWLINE);
- if (bsc->acc_lst_name)
- vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_token,
- cfg_net_bsc_token_cmd,
- "token TOKEN",
- "A token for the BSC to be sent to the MSC\n" "A token\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- osmo_talloc_replace_string(osmo_bsc_data(vty), &data->bsc_token, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_key,
- cfg_net_bsc_key_cmd,
- "auth-key KEY",
- "Authentication (secret) key configuration\n"
- "Security key\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- osmo_hexparse(argv[0], data->bsc_key, sizeof(data->bsc_key));
- data->bsc_key_present = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_no_bsc_key, cfg_net_bsc_no_key_cmd,
- "no auth-key",
- NO_STR "Authentication (secret) key configuration\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- memset(data->bsc_key, 0, sizeof(data->bsc_key));
- data->bsc_key_present = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_ncc,
- cfg_net_bsc_ncc_cmd,
- "core-mobile-network-code <1-999>",
- "Use this network code for the core network\n" "MNC value\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->core_mnc = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_mcc,
- cfg_net_bsc_mcc_cmd,
- "core-mobile-country-code <1-999>",
- "Use this country code for the core network\n" "MCC value\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->core_mcc = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_lac,
- cfg_net_bsc_lac_cmd,
- "core-location-area-code <0-65535>",
- "Use this location area code for the core network\n" "LAC value\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->core_lac = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_ci,
- cfg_net_bsc_ci_cmd,
- "core-cell-identity <0-65535>",
- "Use this cell identity for the core network\n" "CI value\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->core_ci = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_rtp_base,
- cfg_net_bsc_rtp_base_cmd,
- "ip.access rtp-base <1-65000>",
- IPA_STR
- "Set the rtp-base port for the RTP stream\n"
- "Port number\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->rtp_base = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_codec_list,
- cfg_net_bsc_codec_list_cmd,
- "codec-list .LIST",
- "Set the allowed audio codecs\n"
- "List of audio codecs, e.g. fr3 fr1 hr3\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- int saw_fr, saw_hr;
- int i;
-
- saw_fr = saw_hr = 0;
-
- /* free the old list... if it exists */
- if (data->audio_support) {
- talloc_free(data->audio_support);
- data->audio_support = NULL;
- data->audio_length = 0;
- }
-
- /* create a new array */
- data->audio_support =
- talloc_zero_array(osmo_bsc_data(vty), struct gsm_audio_support *, argc);
- data->audio_length = argc;
-
- for (i = 0; i < argc; ++i) {
- /* check for hrX or frX */
- if (strlen(argv[i]) != 3
- || argv[i][1] != 'r'
- || (argv[i][0] != 'h' && argv[i][0] != 'f')
- || argv[i][2] < 0x30
- || argv[i][2] > 0x39)
- goto error;
-
- data->audio_support[i] = talloc_zero(data->audio_support,
- struct gsm_audio_support);
- data->audio_support[i]->ver = atoi(argv[i] + 2);
-
- if (strncmp("hr", argv[i], 2) == 0) {
- data->audio_support[i]->hr = 1;
- saw_hr = 1;
- } else if (strncmp("fr", argv[i], 2) == 0) {
- data->audio_support[i]->hr = 0;
- saw_fr = 1;
- }
-
- if (saw_hr && saw_fr) {
- vty_out(vty, "Can not have full-rate and half-rate codec.%s",
- VTY_NEWLINE);
- return CMD_ERR_INCOMPLETE;
- }
- }
-
- return CMD_SUCCESS;
-
-error:
- vty_out(vty, "Codec name must be hrX or frX. Was '%s'%s",
- argv[i], VTY_NEWLINE);
- return CMD_ERR_INCOMPLETE;
-}
-
-DEFUN(cfg_net_msc_dest,
- cfg_net_msc_dest_cmd,
- "dest A.B.C.D <1-65000> <0-255>",
- "Add a destination to a MUX/MSC\n"
- "IP Address\n" "Port\n" "DSCP\n")
-{
- struct bsc_msc_dest *dest;
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- dest = talloc_zero(osmo_bsc_data(vty), struct bsc_msc_dest);
- if (!dest) {
- vty_out(vty, "%%Failed to create structure.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- dest->ip = talloc_strdup(dest, argv[0]);
- if (!dest->ip) {
- vty_out(vty, "%%Failed to copy dest ip.%s", VTY_NEWLINE);
- talloc_free(dest);
- return CMD_WARNING;
- }
-
- dest->port = atoi(argv[1]);
- dest->dscp = atoi(argv[2]);
- llist_add_tail(&dest->list, &data->dests);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_no_dest,
- cfg_net_msc_no_dest_cmd,
- "no dest A.B.C.D <1-65000> <0-255>",
- NO_STR "Remove a destination to a MUX/MSC\n"
- "IP Address\n" "Port\n" "DSCP\n")
-{
- struct bsc_msc_dest *dest, *tmp;
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- int port = atoi(argv[1]);
- int dscp = atoi(argv[2]);
-
- llist_for_each_entry_safe(dest, tmp, &data->dests, list) {
- if (port != dest->port || dscp != dest->dscp
- || strcmp(dest->ip, argv[0]) != 0)
- continue;
-
- llist_del(&dest->list);
- talloc_free(dest);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_no_ping_time,
- cfg_net_msc_no_ping_time_cmd,
- "no timeout-ping",
- NO_STR "Disable the ping/pong handling on A-link\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->ping_timeout = -1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_ping_time,
- cfg_net_msc_ping_time_cmd,
- "timeout-ping <1-2147483647>",
- "Set the PING interval, negative for not sending PING\n"
- "Timeout in seconds\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->ping_timeout = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_pong_time,
- cfg_net_msc_pong_time_cmd,
- "timeout-pong <1-2147483647>",
- "Set the time to wait for a PONG\n" "Timeout in seconds\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->pong_timeout = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_advanced_ping,
- cfg_net_msc_advanced_ping_cmd,
- "timeout-ping advanced",
- "Ping timeout handling\nEnable advanced mode during SCCP\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- if (data->ping_timeout == -1) {
- vty_out(vty, "%%ping handling is disabled. Enable it first.%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- data->advanced_ping = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_no_net_msc_advanced_ping,
- cfg_no_net_msc_advanced_ping_cmd,
- "no timeout-ping advanced",
- NO_STR "Ping timeout handling\nEnable advanced mode during SCCP\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->advanced_ping = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_welcome_ussd,
- cfg_net_msc_welcome_ussd_cmd,
- "bsc-welcome-text .TEXT",
- "Set the USSD notification to be sent\n" "Text to be sent\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- char *str = argv_concat(argv, argc, 0);
- if (!str)
- return CMD_WARNING;
-
- osmo_talloc_replace_string(osmo_bsc_data(vty), &data->ussd_welcome_txt, str);
- talloc_free(str);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_no_welcome_ussd,
- cfg_net_msc_no_welcome_ussd_cmd,
- "no bsc-welcome-text",
- NO_STR "Clear the USSD notification to be sent\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- talloc_free(data->ussd_welcome_txt);
- data->ussd_welcome_txt = NULL;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_lost_ussd,
- cfg_net_msc_lost_ussd_cmd,
- "bsc-msc-lost-text .TEXT",
- "Set the USSD notification to be sent on MSC connection loss\n" "Text to be sent\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- char *str = argv_concat(argv, argc, 0);
- if (!str)
- return CMD_WARNING;
-
- osmo_talloc_replace_string(osmo_bsc_data(vty), &data->ussd_msc_lost_txt, str);
- talloc_free(str);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_no_lost_ussd,
- cfg_net_msc_no_lost_ussd_cmd,
- "no bsc-msc-lost-text",
- NO_STR "Clear the USSD notification to be sent on MSC connection loss\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- talloc_free(data->ussd_msc_lost_txt);
- data->ussd_msc_lost_txt = 0;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_grace_ussd,
- cfg_net_msc_grace_ussd_cmd,
- "bsc-grace-text .TEXT",
- "Set the USSD notification to be sent when the MSC has entered the grace period\n" "Text to be sent\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- char *str = argv_concat(argv, argc, 0);
- if (!str)
- return CMD_WARNING;
-
- osmo_talloc_replace_string(osmo_bsc_data(vty), &data->ussd_grace_txt, str);
- talloc_free(str);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_no_grace_ussd,
- cfg_net_msc_no_grace_ussd_cmd,
- "no bsc-grace-text",
- NO_STR "Clear the USSD notification to be sent when the MSC has entered the grace period\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- talloc_free(data->ussd_grace_txt);
- data->ussd_grace_txt = NULL;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_missing_msc_ussd,
- cfg_net_bsc_missing_msc_ussd_cmd,
- "missing-msc-text .TEXT",
- "Set the USSD notification to be send when a MSC has not been found.\n" "Text to be sent\n")
-{
- struct osmo_bsc_data *data = osmo_bsc_data(vty);
- char *txt = argv_concat(argv, argc, 0);
- if (!txt)
- return CMD_WARNING;
-
- osmo_talloc_replace_string(data, &data->ussd_no_msc_txt, txt);
- talloc_free(txt);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_no_missing_msc_text,
- cfg_net_bsc_no_missing_msc_text_cmd,
- "no missing-msc-text",
- NO_STR "Clear the USSD notification to be send when a MSC has not been found.\n")
-{
- struct osmo_bsc_data *data = osmo_bsc_data(vty);
-
- talloc_free(data->ussd_no_msc_txt);
- data->ussd_no_msc_txt = 0;
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN(cfg_net_msc_type,
- cfg_net_msc_type_cmd,
- "type (normal|local)",
- "Select the MSC type\n"
- "Plain GSM MSC\n" "Special MSC for local call routing\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
-
- if (strcmp(argv[0], "normal") == 0)
- data->type = MSC_CON_TYPE_NORMAL;
- else if (strcmp(argv[0], "local") == 0)
- data->type = MSC_CON_TYPE_LOCAL;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_emerg,
- cfg_net_msc_emerg_cmd,
- "allow-emergency (allow|deny)",
- "Allow CM ServiceRequests with type emergency\n"
- "Allow\n" "Deny\n")
-{
- struct bsc_msc_data *data = bsc_msc_data(vty);
- data->allow_emerg = strcmp("allow", argv[0]) == 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_msc_local_prefix,
- cfg_net_msc_local_prefix_cmd,
- "local-prefix REGEXP",
- "Prefix for local numbers\n" "REGEXP used\n")
-{
- struct bsc_msc_data *msc = bsc_msc_data(vty);
-
- if (gsm_parse_reg(msc, &msc->local_pref_reg, &msc->local_pref, argc, argv) != 0) {
- vty_out(vty, "%%Failed to parse the regexp: '%s'%s",
- argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-#define AMR_CONF_STR "AMR Multirate Configuration\n"
-#define AMR_COMMAND(name) \
- DEFUN(cfg_net_msc_amr_##name, \
- cfg_net_msc_amr_##name##_cmd, \
- "amr-config " #name "k (allowed|forbidden)", \
- AMR_CONF_STR "Bitrate\n" "Allowed\n" "Forbidden\n") \
-{ \
- struct bsc_msc_data *msc = bsc_msc_data(vty); \
- \
- msc->amr_conf.m##name = strcmp(argv[0], "allowed") == 0; \
- return CMD_SUCCESS; \
-}
-
-AMR_COMMAND(12_2)
-AMR_COMMAND(10_2)
-AMR_COMMAND(7_95)
-AMR_COMMAND(7_40)
-AMR_COMMAND(6_70)
-AMR_COMMAND(5_90)
-AMR_COMMAND(5_15)
-AMR_COMMAND(4_75)
-
-DEFUN(cfg_msc_acc_lst_name,
- cfg_msc_acc_lst_name_cmd,
- "access-list-name NAME",
- "Set the name of the access list to use.\n"
- "The name of the to be used access list.")
-{
- struct bsc_msc_data *msc = bsc_msc_data(vty);
-
- osmo_talloc_replace_string(msc, &msc->acc_lst_name, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_msc_no_acc_lst_name,
- cfg_msc_no_acc_lst_name_cmd,
- "no access-list-name",
- NO_STR "Remove the access list from the NAT.\n")
-{
- struct bsc_msc_data *msc = bsc_msc_data(vty);
-
- if (msc->acc_lst_name) {
- talloc_free(msc->acc_lst_name);
- msc->acc_lst_name = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-/* Make sure only standard SSN numbers are used. If no ssn number is
- * configured, silently apply the default SSN */
-static void enforce_standard_ssn(struct vty *vty, struct osmo_sccp_addr *addr)
-{
- if (addr->presence & OSMO_SCCP_ADDR_T_SSN) {
- if (addr->ssn != SCCP_SSN_BSSAP)
- vty_out(vty,
- "setting an SSN (%u) different from the standard (%u) is not allowd, will use standard SSN for address: %s%s",
- addr->ssn, SCCP_SSN_BSSAP, osmo_sccp_addr_dump(addr), VTY_NEWLINE);
- }
-
- addr->presence |= OSMO_SCCP_ADDR_T_SSN;
- addr->ssn = SCCP_SSN_BSSAP;
-}
-
-DEFUN(cfg_msc_cs7_bsc_addr,
- cfg_msc_cs7_bsc_addr_cmd,
- "bsc-addr NAME",
- "Calling Address (local address of this BSC)\n" "SCCP address name\n")
-{
- struct bsc_msc_data *msc = bsc_msc_data(vty);
- const char *bsc_addr_name = argv[0];
- struct osmo_ss7_instance *ss7;
-
- ss7 = osmo_sccp_addr_by_name(&msc->a.bsc_addr, bsc_addr_name);
- if (!ss7) {
- vty_out(vty, "No sccp address %s found%s", bsc_addr_name,
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* Prevent mixing addresses from different CS7/SS7 instances */
- if (msc->a.cs7_instance_valid) {
- if (msc->a.cs7_instance != ss7->cfg.id) {
- vty_out(vty,
- "SCCP address %s from different CS7 instance%s",
- bsc_addr_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- msc->a.cs7_instance = ss7->cfg.id;
- msc->a.cs7_instance_valid = true;
- enforce_standard_ssn(vty, &msc->a.bsc_addr);
- msc->a.bsc_addr_name = talloc_strdup(msc, bsc_addr_name);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_msc_cs7_msc_addr,
- cfg_msc_cs7_msc_addr_cmd,
- "msc-addr NAME",
- "Called Address (remote address of the MSC)\n" "SCCP address name\n")
-{
- struct bsc_msc_data *msc = bsc_msc_data(vty);
- const char *msc_addr_name = argv[0];
- struct osmo_ss7_instance *ss7;
-
- ss7 = osmo_sccp_addr_by_name(&msc->a.msc_addr, msc_addr_name);
- if (!ss7) {
- vty_out(vty, "No sccp address %s found%s", msc_addr_name,
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* Prevent mixing addresses from different CS7/SS7 instances */
- if (msc->a.cs7_instance_valid) {
- if (msc->a.cs7_instance != ss7->cfg.id) {
- vty_out(vty,
- "SCCP address %s from different CS7 instance%s",
- msc_addr_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- msc->a.cs7_instance = ss7->cfg.id;
- msc->a.cs7_instance_valid = true;
- enforce_standard_ssn(vty, &msc->a.msc_addr);
- msc->a.msc_addr_name = talloc_strdup(msc, msc_addr_name);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_mid_call_text,
- cfg_net_bsc_mid_call_text_cmd,
- "mid-call-text .TEXT",
- "Set the USSD notification to be send.\n" "Text to be sent\n")
-{
- struct osmo_bsc_data *data = osmo_bsc_data(vty);
- char *txt = argv_concat(argv, argc, 0);
- if (!txt)
- return CMD_WARNING;
-
- osmo_talloc_replace_string(data, &data->mid_call_txt, txt);
- talloc_free(txt);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_bsc_mid_call_timeout,
- cfg_net_bsc_mid_call_timeout_cmd,
- "mid-call-timeout NR",
- "Switch from Grace to Off in NR seconds.\n" "Timeout in seconds\n")
-{
- struct osmo_bsc_data *data = osmo_bsc_data(vty);
- data->mid_call_timeout = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_rf_socket,
- cfg_net_rf_socket_cmd,
- "bsc-rf-socket PATH",
- "Set the filename for the RF control interface.\n" "RF Control path\n")
-{
- struct osmo_bsc_data *data = osmo_bsc_data(vty);
-
- osmo_talloc_replace_string(data, &data->rf_ctrl_name, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_rf_off_time,
- cfg_net_rf_off_time_cmd,
- "bsc-auto-rf-off <1-65000>",
- "Disable RF on MSC Connection\n" "Timeout\n")
-{
- struct osmo_bsc_data *data = osmo_bsc_data(vty);
- data->auto_off_timeout = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_no_rf_off_time,
- cfg_net_no_rf_off_time_cmd,
- "no bsc-auto-rf-off",
- NO_STR "Disable RF on MSC Connection\n")
-{
- struct osmo_bsc_data *data = osmo_bsc_data(vty);
- data->auto_off_timeout = -1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_acc_lst_name,
- cfg_bsc_acc_lst_name_cmd,
- "access-list-name NAME",
- "Set the name of the access list to use.\n"
- "The name of the to be used access list.")
-{
- struct osmo_bsc_data *bsc = osmo_bsc_data(vty);
-
- osmo_talloc_replace_string(bsc, &bsc->acc_lst_name, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_no_acc_lst_name,
- cfg_bsc_no_acc_lst_name_cmd,
- "no access-list-name",
- NO_STR "Remove the access list from the BSC\n")
-{
- struct osmo_bsc_data *bsc = osmo_bsc_data(vty);
-
- if (bsc->acc_lst_name) {
- talloc_free(bsc->acc_lst_name);
- bsc->acc_lst_name = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_statistics,
- show_statistics_cmd,
- "show statistics",
- SHOW_STR "Statistics about the BSC\n")
-{
- openbsc_vty_print_statistics(vty, bsc_gsmnet);
- return CMD_SUCCESS;
-}
-
-DEFUN(show_mscs,
- show_mscs_cmd,
- "show mscs",
- SHOW_STR "MSC Connections and State\n")
-{
- struct bsc_msc_data *msc;
- llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry) {
- vty_out(vty, "MSC Nr: %d is connected: %d auth: %d.%s",
- msc->nr,
- msc->msc_con ? msc->msc_con->is_connected : -1,
- msc->msc_con ? msc->msc_con->is_authenticated : -1,
- VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_pos,
- show_pos_cmd,
- "show position",
- SHOW_STR "Position information of the BTS\n")
-{
- struct gsm_bts *bts;
- struct bts_location *curloc;
- struct tm time;
- char timestr[50];
-
- llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
- if (llist_empty(&bts->loc_list)) {
- vty_out(vty, "BTS Nr: %d position invalid%s", bts->nr,
- VTY_NEWLINE);
- continue;
- }
- curloc = llist_entry(bts->loc_list.next, struct bts_location, list);
- if (gmtime_r(&curloc->tstamp, &time) == NULL) {
- vty_out(vty, "Time conversion failed for BTS %d%s", bts->nr,
- VTY_NEWLINE);
- continue;
- }
- if (asctime_r(&time, timestr) == NULL) {
- vty_out(vty, "Time conversion failed for BTS %d%s", bts->nr,
- VTY_NEWLINE);
- continue;
- }
- /* Last character in asctime is \n */
- timestr[strlen(timestr)-1] = 0;
-
- vty_out(vty, "BTS Nr: %d position: %s time: %s%s", bts->nr,
- get_value_string(bts_loc_fix_names, curloc->valid), timestr,
- VTY_NEWLINE);
- vty_out(vty, " lat: %f lon: %f height: %f%s", curloc->lat, curloc->lon,
- curloc->height, VTY_NEWLINE);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN(gen_position_trap,
- gen_position_trap_cmd,
- "generate-location-state-trap <0-255>",
- "Generate location state report\n"
- "BTS to report\n")
-{
- int bts_nr;
- struct gsm_bts *bts;
- struct gsm_network *net = bsc_gsmnet;
-
- bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
- vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts = gsm_bts_num(net, bts_nr);
- bsc_gen_location_state_trap(bts);
- return CMD_SUCCESS;
-}
-
-DEFUN(logging_fltr_imsi,
- logging_fltr_imsi_cmd,
- "logging filter imsi IMSI",
- LOGGING_STR FILTER_STR
- "Filter log messages by IMSI\n" "IMSI to be used as filter\n")
-{
- struct bsc_subscr *bsc_subscr;
- struct log_target *tgt = osmo_log_vty2tgt(vty);
- const char *imsi = argv[0];
-
- bsc_subscr = bsc_subscr_find_by_imsi(bsc_gsmnet->bsc_subscribers, imsi);
-
- if (!bsc_subscr) {
- vty_out(vty, "%%no subscriber with IMSI(%s)%s",
- imsi, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- log_set_filter_bsc_subscr(tgt, bsc_subscr);
- return CMD_SUCCESS;
-}
-
-int bsc_vty_init_extra(void)
-{
- install_element(CONFIG_NODE, &cfg_net_msc_cmd);
- install_element(CONFIG_NODE, &cfg_net_bsc_cmd);
-
- install_node(&bsc_node, config_write_bsc);
- vty_install_default(BSC_NODE);
- install_element(BSC_NODE, &cfg_net_bsc_mid_call_text_cmd);
- install_element(BSC_NODE, &cfg_net_bsc_mid_call_timeout_cmd);
- install_element(BSC_NODE, &cfg_net_rf_socket_cmd);
- install_element(BSC_NODE, &cfg_net_rf_off_time_cmd);
- install_element(BSC_NODE, &cfg_net_no_rf_off_time_cmd);
- install_element(BSC_NODE, &cfg_net_bsc_missing_msc_ussd_cmd);
- install_element(BSC_NODE, &cfg_net_bsc_no_missing_msc_text_cmd);
- install_element(BSC_NODE, &cfg_bsc_acc_lst_name_cmd);
- install_element(BSC_NODE, &cfg_bsc_no_acc_lst_name_cmd);
-
- install_node(&msc_node, config_write_msc);
- vty_install_default(MSC_NODE);
- install_element(MSC_NODE, &cfg_net_bsc_token_cmd);
- install_element(MSC_NODE, &cfg_net_bsc_key_cmd);
- install_element(MSC_NODE, &cfg_net_bsc_no_key_cmd);
- install_element(MSC_NODE, &cfg_net_bsc_ncc_cmd);
- install_element(MSC_NODE, &cfg_net_bsc_mcc_cmd);
- install_element(MSC_NODE, &cfg_net_bsc_lac_cmd);
- install_element(MSC_NODE, &cfg_net_bsc_ci_cmd);
- install_element(MSC_NODE, &cfg_net_bsc_rtp_base_cmd);
- install_element(MSC_NODE, &cfg_net_bsc_codec_list_cmd);
- install_element(MSC_NODE, &cfg_net_msc_dest_cmd);
- install_element(MSC_NODE, &cfg_net_msc_no_dest_cmd);
- install_element(MSC_NODE, &cfg_net_msc_no_ping_time_cmd);
- install_element(MSC_NODE, &cfg_net_msc_ping_time_cmd);
- install_element(MSC_NODE, &cfg_net_msc_pong_time_cmd);
- install_element(MSC_NODE, &cfg_net_msc_advanced_ping_cmd);
- install_element(MSC_NODE, &cfg_no_net_msc_advanced_ping_cmd);
- install_element(MSC_NODE, &cfg_net_msc_welcome_ussd_cmd);
- install_element(MSC_NODE, &cfg_net_msc_no_welcome_ussd_cmd);
- install_element(MSC_NODE, &cfg_net_msc_lost_ussd_cmd);
- install_element(MSC_NODE, &cfg_net_msc_no_lost_ussd_cmd);
- install_element(MSC_NODE, &cfg_net_msc_grace_ussd_cmd);
- install_element(MSC_NODE, &cfg_net_msc_no_grace_ussd_cmd);
- install_element(MSC_NODE, &cfg_net_msc_type_cmd);
- install_element(MSC_NODE, &cfg_net_msc_emerg_cmd);
- install_element(MSC_NODE, &cfg_net_msc_local_prefix_cmd);
- install_element(MSC_NODE, &cfg_net_msc_amr_12_2_cmd);
- install_element(MSC_NODE, &cfg_net_msc_amr_10_2_cmd);
- install_element(MSC_NODE, &cfg_net_msc_amr_7_95_cmd);
- install_element(MSC_NODE, &cfg_net_msc_amr_7_40_cmd);
- install_element(MSC_NODE, &cfg_net_msc_amr_6_70_cmd);
- install_element(MSC_NODE, &cfg_net_msc_amr_5_90_cmd);
- install_element(MSC_NODE, &cfg_net_msc_amr_5_15_cmd);
- install_element(MSC_NODE, &cfg_net_msc_amr_4_75_cmd);
- install_element(MSC_NODE, &cfg_msc_acc_lst_name_cmd);
- install_element(MSC_NODE, &cfg_msc_no_acc_lst_name_cmd);
- install_element(MSC_NODE, &cfg_msc_cs7_bsc_addr_cmd);
- install_element(MSC_NODE, &cfg_msc_cs7_msc_addr_cmd);
-
- install_element_ve(&show_statistics_cmd);
- install_element_ve(&show_mscs_cmd);
- install_element_ve(&show_pos_cmd);
- install_element_ve(&logging_fltr_imsi_cmd);
-
- install_element(ENABLE_NODE, &gen_position_trap_cmd);
-
- install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);
-
- return 0;
-}