aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/bsc_init.c
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-05-27 01:26:31 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2018-06-07 19:09:06 +0200
commit958f259f9592e3729a2ebf4084d8f37bdba6bf3c (patch)
tree3ca9a7de640b28ef6f40578df4c036440f8a4cb1 /src/osmo-bsc/bsc_init.c
parent8f2aaf47c910a984de370774e6910ea5d453983e (diff)
dissolve libbsc: move all to src/osmo-bsc, link .o files
Move all of libbsc/ into osmo-bsc/, and separate/move some implementations to allow linking from utils/* and ipaccess/* without pulling in unccessary dependencies. Some utilities use gsm_network and gsm_bts structs, which already include data structures for fairly advanced uses. Move initialization that only osmo-bsc needs into new bsc_network_init() and bsc_bts_alloc_register() functions, so that the leaner tools can use the old gsm_* versions without the need to link everything (e.g. handover and lchan alloc code). In some instances, there need to be stubs if to cut off linking "just before the RSL level" and prevent dependencies from creeping in. - abis_rsl_rcvmsg(): the only program currently interpreting RSL messages is osmo-bsc, the utils are merely concerned with OML, if at all. - paging_flush_bts(): ip.access nanobts models call this when the RSL link is dropped. Only osmo-bsc actually needs to do anything there. - on_gsm_ts_init(): the mechanism to trigger timeslot initialization is related to OML, while this action to take on init would pull in RSL dependencies. utils/ and ipaccess/ each have a stubs.c file to implement these stubs. Tests implement stubs inline where required. From src/utils/, src/ipaccess/ and tests/*/, link in .o files from osmo-bsc/. In order for this to work, the osmo-bsc subdir must be built before the other source trees. (An alternative would be to include the .c files as sources, but that would re-compile them in every source tree. Not a large burden really, but unless linking .o files gives problems, let's have the quicker build.) Minor obvious cleanups creep in with this patch, I will not bother to name them individually now unless code review asks me to. Rationale: 1) libbsc has been separate to use it for osmo-nitb and osmo-bsc in the old openbsc.git. This is no longer required, and spreading over libbsc and osmo-bsc is distracting. 2) Recently, ridiculous linking requirements have made adding new functions cumbersome, because libbsc has started depending on osmo-bsc/*.c implementations: on gscon FSM and bssap functions. For example, neither bs11_config nor ipaccess-config nor bts_test need handover_cfg or BSSMAP message composition. It makes no sense to link the entire osmo-bsc to it, nor do we want to keep adding stubs to each linking realm. Change-Id: I36a586726f5818121abe54d25654819fc451d3bf
Diffstat (limited to 'src/osmo-bsc/bsc_init.c')
-rw-r--r--src/osmo-bsc/bsc_init.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/osmo-bsc/bsc_init.c b/src/osmo-bsc/bsc_init.c
new file mode 100644
index 000000000..b6bd41025
--- /dev/null
+++ b/src/osmo-bsc/bsc_init.c
@@ -0,0 +1,288 @@
+/* A hackish minimal BSC (+MSC +HLR) implementation */
+
+/* (C) 2008-2018 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * 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/bsc/gsm_data.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/bsc/abis_rsl.h>
+#include <osmocom/bsc/debug.h>
+#include <osmocom/bsc/misdn.h>
+#include <osmocom/bsc/system_information.h>
+#include <osmocom/bsc/paging.h>
+#include <osmocom/bsc/signal.h>
+#include <osmocom/bsc/chan_alloc.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/bsc/ipaccess.h>
+#include <osmocom/gsm/sysinfo.h>
+#include <osmocom/bsc/pcu_if.h>
+#include <osmocom/bsc/bsc_msc_data.h>
+#include <osmocom/bsc/handover_cfg.h>
+#include <osmocom/bsc/gsm_04_08_utils.h>
+
+#include <time.h>
+#include <limits.h>
+#include <stdbool.h>
+
+int bsc_shutdown_net(struct gsm_network *net)
+{
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &net->bts_list, list) {
+ LOGP(DNM, LOGL_NOTICE, "shutting down OML for BTS %u\n", bts->nr);
+ osmo_signal_dispatch(SS_L_GLOBAL, S_GLOBAL_BTS_CLOSE_OM, bts);
+ }
+
+ return 0;
+}
+
+unsigned long long bts_uptime(const struct gsm_bts *bts)
+{
+ struct timespec tp;
+
+ if (!bts->uptime || !bts->oml_link) {
+ LOGP(DNM, LOGL_ERROR, "BTS %u OML link uptime unavailable\n", bts->nr);
+ return 0;
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0) {
+ LOGP(DNM, LOGL_ERROR, "BTS %u uptime computation failure: %s\n", bts->nr, strerror(errno));
+ return 0;
+ }
+
+ /* monotonic clock helps to ensure that the conversion is valid */
+ return difftime(tp.tv_sec, bts->uptime);
+}
+
+static int rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i, int si_len)
+{
+ struct gsm_bts *bts = trx->bts;
+ int rc, j;
+
+ if (si_len) {
+ DEBUGP(DRR, "SI%s: %s\n", get_value_string(osmo_sitype_strs, i),
+ osmo_hexdump(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN));
+ } else
+ DEBUGP(DRR, "SI%s: OFF\n", get_value_string(osmo_sitype_strs, i));
+
+ switch (i) {
+ case SYSINFO_TYPE_5:
+ case SYSINFO_TYPE_5bis:
+ case SYSINFO_TYPE_5ter:
+ case SYSINFO_TYPE_6:
+ rc = rsl_sacch_filling(trx, osmo_sitype2rsl(i),
+ si_len ? GSM_BTS_SI(bts, i) : NULL, si_len);
+ break;
+ case SYSINFO_TYPE_2quater:
+ if (si_len == 0) {
+ rc = rsl_bcch_info(trx, i, NULL, 0);
+ break;
+ }
+ rc = 0;
+ for (j = 0; j <= bts->si2q_count; j++)
+ rc = rsl_bcch_info(trx, i, (const uint8_t *)GSM_BTS_SI2Q(bts, j), GSM_MACBLOCK_LEN);
+ break;
+ default:
+ rc = rsl_bcch_info(trx, i, si_len ? GSM_BTS_SI(bts, i) : NULL, si_len);
+ break;
+ }
+
+ return rc;
+}
+
+/* set all system information types for a TRX */
+int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx)
+{
+ int i, rc;
+ struct gsm_bts *bts = trx->bts;
+ uint8_t gen_si[_MAX_SYSINFO_TYPE], n_si = 0, n;
+ int si_len[_MAX_SYSINFO_TYPE];
+
+ bts->si_common.cell_sel_par.ms_txpwr_max_ccch =
+ ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
+ bts->si_common.cell_sel_par.neci = bts->network->neci;
+
+ /* Zero/forget the state of the dynamically computed SIs, leeping the static ones */
+ bts->si_valid = bts->si_mode_static;
+
+ /* First, we determine which of the SI messages we actually need */
+
+ if (trx == bts->c0) {
+ /* 1...4 are always present on a C0 TRX */
+ gen_si[n_si++] = SYSINFO_TYPE_1;
+ gen_si[n_si++] = SYSINFO_TYPE_2;
+ gen_si[n_si++] = SYSINFO_TYPE_2bis;
+ gen_si[n_si++] = SYSINFO_TYPE_2ter;
+ gen_si[n_si++] = SYSINFO_TYPE_2quater;
+ gen_si[n_si++] = SYSINFO_TYPE_3;
+ gen_si[n_si++] = SYSINFO_TYPE_4;
+
+ /* 13 is always present on a C0 TRX of a GPRS BTS */
+ if (bts->gprs.mode != BTS_GPRS_NONE)
+ gen_si[n_si++] = SYSINFO_TYPE_13;
+ }
+
+ /* 5 and 6 are always present on every TRX */
+ gen_si[n_si++] = SYSINFO_TYPE_5;
+ gen_si[n_si++] = SYSINFO_TYPE_5bis;
+ gen_si[n_si++] = SYSINFO_TYPE_5ter;
+ gen_si[n_si++] = SYSINFO_TYPE_6;
+
+ /* Second, we generate the selected SI via RSL */
+
+ for (n = 0; n < n_si; n++) {
+ i = gen_si[n];
+ /* Only generate SI if this SI is not in "static" (user-defined) mode */
+ if (!(bts->si_mode_static & (1 << i))) {
+ /* Set SI as being valid. gsm_generate_si() might unset
+ * it, if SI is not required. */
+ bts->si_valid |= (1 << i);
+ rc = gsm_generate_si(bts, i);
+ if (rc < 0)
+ goto err_out;
+ si_len[i] = rc;
+ } else {
+ if (i == SYSINFO_TYPE_5 || i == SYSINFO_TYPE_5bis
+ || i == SYSINFO_TYPE_5ter)
+ si_len[i] = 18;
+ else if (i == SYSINFO_TYPE_6)
+ si_len[i] = 11;
+ else
+ si_len[i] = 23;
+ }
+ }
+
+ /* Third, we send the selected SI via RSL */
+
+ for (n = 0; n < n_si; n++) {
+ i = gen_si[n];
+ /* if we don't currently have this SI, we send a zero-length
+ * RSL BCCH FILLING / SACCH FILLING * in order to deactivate
+ * the SI, in case it might have previously been active */
+ if (!GSM_BTS_HAS_SI(bts, i))
+ rc = rsl_si(trx, i, 0);
+ else
+ rc = rsl_si(trx, i, si_len[i]);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* Make sure the PCU is aware (in case anything GPRS related has
+ * changed in SI */
+ pcu_info_update(bts);
+
+ return 0;
+err_out:
+ LOGP(DRR, LOGL_ERROR, "Cannot generate SI%s for BTS %u: error <%s>, "
+ "most likely a problem with neighbor cell list generation\n",
+ get_value_string(osmo_sitype_strs, i), bts->nr, strerror(-rc));
+ return rc;
+}
+
+/* set all system information types for a BTS */
+int gsm_bts_set_system_infos(struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+
+ /* Generate a new ID */
+ bts->bcch_change_mark += 1;
+ bts->bcch_change_mark %= 0x7;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ int rc;
+
+ rc = gsm_bts_trx_set_system_infos(trx);
+ if (rc != 0)
+ return rc;
+ }
+
+ return 0;
+}
+
+/* XXX hard-coded for now */
+#define T3122_CHAN_LOAD_SAMPLE_INTERVAL 1 /* in seconds */
+
+static void update_t3122_chan_load_timer(void *data)
+{
+ struct gsm_network *net = data;
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &net->bts_list, list)
+ bts_update_t3122_chan_load(bts);
+
+ /* Keep this timer ticking. */
+ osmo_timer_schedule(&net->t3122_chan_load_timer, T3122_CHAN_LOAD_SAMPLE_INTERVAL, 0);
+}
+
+static struct gsm_network *bsc_network_init(void *ctx)
+{
+ struct gsm_network *net = gsm_network_init(ctx);
+
+ net->bsc_data = talloc_zero(net, struct osmo_bsc_data);
+ if (!net->bsc_data) {
+ talloc_free(net);
+ return NULL;
+ }
+
+ /* Init back pointer */
+ net->bsc_data->auto_off_timeout = -1;
+ net->bsc_data->network = net;
+ INIT_LLIST_HEAD(&net->bsc_data->mscs);
+
+ net->ho = ho_cfg_init(net, NULL);
+ net->hodec2.congestion_check_interval_s = HO_CFG_CONGESTION_CHECK_DEFAULT;
+
+ /* init statistics */
+ net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0);
+ if (!net->bsc_ctrs) {
+ talloc_free(net);
+ return NULL;
+ }
+
+ gsm_net_update_ctype(net);
+
+ /*
+ * At present all BTS in the network share one channel load timeout.
+ * If this becomes a problem for networks with a lot of BTS, this
+ * code could be refactored to run the timeout individually per BTS.
+ */
+ osmo_timer_setup(&net->t3122_chan_load_timer, update_t3122_chan_load_timer, net);
+ osmo_timer_schedule(&net->t3122_chan_load_timer, T3122_CHAN_LOAD_SAMPLE_INTERVAL, 0);
+
+ return net;
+}
+
+int bsc_network_alloc(void)
+{
+ /* initialize our data structures */
+ bsc_gsmnet = bsc_network_init(tall_bsc_ctx);
+ if (!bsc_gsmnet)
+ return -ENOMEM;
+
+ return 0;
+}
+
+struct gsm_bts *bsc_bts_alloc_register(struct gsm_network *net, enum gsm_bts_type type, uint8_t bsic)
+{
+ struct gsm_bts *bts = gsm_bts_alloc_register(net, type, bsic);
+
+ bts->ho = ho_cfg_init(bts, net->ho);
+
+ return bts;
+}