aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/osmo_bsc_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bsc/osmo_bsc_main.c')
-rw-r--r--src/osmo-bsc/osmo_bsc_main.c460
1 files changed, 258 insertions, 202 deletions
diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c
index 7eaa18ffd..5ad13ca34 100644
--- a/src/osmo-bsc/osmo_bsc_main.c
+++ b/src/osmo-bsc/osmo_bsc_main.c
@@ -57,6 +57,7 @@
#include <osmocom/vty/cpu_sched_vty.h>
#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
+#include <osmocom/mgcp_client/mgcp_client_pool.h>
#include <osmocom/abis/abis.h>
#include <osmocom/bsc/abis_om2000.h>
@@ -67,8 +68,10 @@
#include <osmocom/bsc/codec_pref.h>
#include <osmocom/bsc/system_information.h>
#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/bsc_stats.h>
#include <osmocom/mgcp_client/mgcp_client.h>
+#include <osmocom/mgcp_client/mgcp_client_pool.h>
#include <osmocom/sigtran/xua_msg.h>
@@ -84,19 +87,18 @@
#include "../../bscconfig.h"
-struct gsm_network *bsc_gsmnet = 0;
static const char *config_file = "osmo-bsc.cfg";
static const char *rf_ctrl = NULL;
static int daemonize = 0;
-static void print_usage()
+static void print_usage(void)
{
printf("Usage: osmo-bsc\n");
}
-static void print_help()
+static void print_help(void)
{
- printf(" Some useful help...\n");
+ printf("Some useful options:\n");
printf(" -h --help This text.\n");
printf(" -D --daemonize Fork the process into a background daemon.\n");
printf(" -d --debug option --debug=DRLL:DMM:DRR:DRSL:DNM enable debugging.\n");
@@ -104,11 +106,37 @@ static void print_help()
printf(" -T --timestamp Print a timestamp in the debug output.\n");
printf(" -V --version Print the version of OsmoBSC.\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");
- printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
+
+ printf("\nVTY reference generation:\n");
+ printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
+ printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
+}
+
+static void handle_long_options(const char *prog_name, const int long_option)
+{
+ static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
+
+ switch (long_option) {
+ case 1:
+ vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
+ if (vty_ref_mode < 0) {
+ fprintf(stderr, "%s: Unknown VTY reference generation "
+ "mode '%s'\n", prog_name, optarg);
+ exit(2);
+ }
+ break;
+ case 2:
+ fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
+ get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
+ get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
+ vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
+ exit(0);
+ default:
+ fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
+ exit(2);
+ }
}
static void handle_options(int argc, char **argv)
@@ -124,15 +152,14 @@ static void handle_options(int argc, char **argv)
{"disable-color", 0, 0, 's'},
{"timestamp", 0, 0, 'T'},
{"version", 0, 0, 'V' },
- {"local", 1, 0, 'l'},
{"log-level", 1, 0, 'e'},
{"rf-ctl", 1, 0, 'r'},
- {"testmode", 0, 0, 't'},
- {"vty-ref-xml", 0, &long_option, 1},
+ {"vty-ref-mode", 1, &long_option, 1},
+ {"vty-ref-xml", 0, &long_option, 2},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "hd:DsTVc:e:r:t",
+ c = getopt_long(argc, argv, "hd:DsTVc:e:r:",
long_options, &option_index);
if (c == -1)
break;
@@ -143,14 +170,8 @@ static void handle_options(int argc, char **argv)
print_help();
exit(0);
case 0:
- switch (long_option) {
- case 1:
- vty_dump_xml_ref(stdout);
- exit(0);
- default:
- fprintf(stderr, "error parsing cmdline options\n");
- exit(2);
- }
+ handle_long_options(argv[0], long_option);
+ break;
case 's':
log_set_use_color(osmo_stderr_target, 0);
break;
@@ -233,14 +254,14 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal,
}
/* Produce a MA as specified in 10.5.2.21 */
-static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
+static void generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
{
/* we have three bitvecs: the per-timeslot ARFCNs, the cell chan ARFCNs
* and the MA */
+ const size_t num_cell_arfcns = ts->trx->bts->si_common.cell_chan_num;
const struct bitvec *cell_chan = &ts->trx->bts->si_common.cell_alloc;
const struct bitvec *ts_arfcn = &ts->hopping.arfcns;
struct bitvec *ma = &ts->hopping.ma;
- unsigned int num_cell_arfcns;
int i;
/* re-set the MA to all-zero */
@@ -248,14 +269,7 @@ static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
memset(ma->data, 0, ma->data_len);
if (!ts->hopping.enabled)
- return 0;
-
- /* count the number of ARFCNs in the cell channel allocation */
- num_cell_arfcns = 0;
- for (i = 0; i < 1024; i++) {
- if (bitvec_get_bit_pos(cell_chan, i))
- num_cell_arfcns++;
- }
+ return;
/* pad it to octet-aligned number of bits */
ts->hopping.ma_len = OSMO_BYTES_FOR_BITS(num_cell_arfcns);
@@ -280,13 +294,26 @@ static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
else
bitvec_set_bit_pos(ma, ma->cur_bit, 0);
}
+}
- return 0;
+static void generate_ma_for_bts(struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+ unsigned int tn;
+
+ OSMO_ASSERT(bts->si_common.cell_chan_num > 0);
+ OSMO_ASSERT(bts->si_common.cell_chan_num <= 64);
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++)
+ generate_ma_for_ts(&trx->ts[tn]);
+ }
}
static void bootstrap_rsl(struct gsm_bts_trx *trx)
{
unsigned int i;
+ int rc;
LOG_TRX(trx, DRSL, LOGL_NOTICE, "bootstrapping RSL "
"on ARFCN %u using MCC-MNC %s LAC=%u CID=%u BSIC=%u\n",
@@ -317,29 +344,73 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx)
rsl_nokia_si_end(trx);
}
+ if (trx->bts->model->power_ctrl_send_def_params != NULL) {
+ rc = trx->bts->model->power_ctrl_send_def_params(trx);
+ if (rc) {
+ LOG_TRX(trx, DRSL, LOGL_ERROR, "Failed to send default "
+ "MS/BS Power control parameters (rc=%d)\n", rc);
+ /* TODO: should we drop RSL connection here? */
+ }
+ }
+
for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
struct gsm_bts_trx_ts *ts = &trx->ts[i];
- generate_ma_for_ts(ts);
OSMO_ASSERT(ts->fi);
osmo_fsm_inst_dispatch(ts->fi, TS_EV_RSL_READY, NULL);
}
- /* Start CBCH transmit timer if CBCH is present */
- if (trx->nr == 0 && gsm_bts_get_cbch(trx->bts))
- bts_cbch_timer_schedule(trx->bts);
-
/* Drop all expired channel requests in the list */
abis_rsl_chan_rqd_queue_flush(trx->bts);
}
-static void all_ts_dispatch_event(struct gsm_bts_trx *trx, uint32_t event)
+struct osmo_timer_list update_connection_stats_timer;
+
+/* Periodically call bsc_update_connection_stats() to keep stat items updated.
+ * It would be nicer to trigger this only when OML or RSL state is seen to flip. I tried hard to find all code paths
+ * that should call this and failed to get accurate results; this trivial timer covers all of them. */
+static void update_connection_stats_cb(void *data)
+{
+ bsc_update_connection_stats(bsc_gsmnet);
+ osmo_timer_setup(&update_connection_stats_timer, update_connection_stats_cb, NULL);
+ osmo_timer_schedule(&update_connection_stats_timer, 1, 0);
+}
+
+static void bootstrap_bts(struct gsm_bts *bts)
{
- int ts_i;
- for (ts_i = 0; ts_i < ARRAY_SIZE(trx->ts); ts_i++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[ts_i];
- if (ts->fi)
- osmo_fsm_inst_dispatch(ts->fi, event, 0);
+ unsigned int n = 0;
+
+ /* Control Channel Description is set from vty/config */
+
+ /* Determine the value of CCCH_CONF. Is TS0/C0 combined? */
+ if (bts->c0->ts[0].pchan_from_config != GSM_PCHAN_CCCH) {
+ bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
+
+ /* Limit reserved block to 2 on combined channel according to
+ 3GPP TS 44.018 Table 10.5.2.11.1 */
+ if (bts->si_common.chan_desc.bs_ag_blks_res > 2) {
+ LOGP(DNM, LOGL_NOTICE, "CCCH is combined with SDCCHs, "
+ "reducing BS-AG-BLKS-RES value %d -> 2\n",
+ bts->si_common.chan_desc.bs_ag_blks_res);
+ bts->si_common.chan_desc.bs_ag_blks_res = 2;
+ }
+ } else { /* Non-combined TS0/C0 configuration */
+ /* There can be additional CCCHs on even timeslot numbers */
+ n += (bts->c0->ts[2].pchan_from_config == GSM_PCHAN_CCCH);
+ n += (bts->c0->ts[4].pchan_from_config == GSM_PCHAN_CCCH);
+ n += (bts->c0->ts[6].pchan_from_config == GSM_PCHAN_CCCH);
+ bts->si_common.chan_desc.ccch_conf = (n << 1);
}
+
+ bts_setup_ramp_init_bts(bts);
+
+ /* ACC ramping is initialized from vty/config */
+
+ /* Initialize the BTS state */
+ gsm_bts_sm_mo_reset(bts->site_mgr);
+
+ /* Generate Mobile Allocation bit-masks for all timeslots.
+ * This needs to be done here, because it's used for TS configuration. */
+ generate_ma_for_bts(bts);
}
/* Callback function to be called every time we receive a signal from INPUT */
@@ -348,13 +419,7 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
{
struct input_signal_data *isd = signal_data;
struct gsm_bts_trx *trx = isd->trx;
- /* N. B: we rely on attribute order when parsing response in abis_nm_rx_get_attr_resp() */
- const uint8_t bts_attr[] = { NM_ATT_MANUF_ID, NM_ATT_SW_CONFIG, };
- const uint8_t trx_attr[] = { NM_ATT_MANUF_STATE, NM_ATT_SW_CONFIG, };
-
- /* we should not request more attributes than we're ready to handle */
- OSMO_ASSERT(sizeof(bts_attr) < MAX_BTS_ATTR);
- OSMO_ASSERT(sizeof(trx_attr) < MAX_BTS_ATTR);
+ int rc;
if (subsys != SS_L_INPUT)
return -EINVAL;
@@ -364,44 +429,43 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
switch (signal) {
case S_L_INP_TEI_UP:
if (isd->link_type == E1INP_SIGN_OML) {
- /* TODO: this is required for the Nokia BTS, hopping is configured
- during OML, other MA is not set. */
- struct gsm_bts_trx *cur_trx;
- uint8_t ca[20];
- /* has to be called before generate_ma_for_ts to
- set bts->si_common.cell_alloc */
- generate_cell_chan_list(ca, trx->bts);
-
- /* Request generic BTS-level attributes */
- abis_nm_get_attr(trx->bts, NM_OC_BTS, 0xFF, 0xFF, 0xFF, bts_attr, sizeof(bts_attr));
-
- llist_for_each_entry(cur_trx, &trx->bts->trx_list, list) {
- int i;
- /* Request TRX-level attributes */
- abis_nm_get_attr(cur_trx->bts, NM_OC_BASEB_TRANSC, 0, cur_trx->nr, 0xFF,
- trx_attr, sizeof(trx_attr));
- for (i = 0; i < ARRAY_SIZE(cur_trx->ts); i++)
- generate_ma_for_ts(&cur_trx->ts[i]);
+ /* Check parameters and apply vty config dependent parameters */
+ rc = gsm_bts_check_cfg(trx->bts);
+ if (rc < 0) {
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) Error in BTS configuration -- cannot bootstrap BTS\n",
+ trx->bts->nr);
+ return rc;
}
+ bootstrap_bts(trx->bts);
}
- if (isd->link_type == E1INP_SIGN_RSL)
+ if (isd->link_type == E1INP_SIGN_RSL) {
+ rc = gsm_bts_check_cfg(trx->bts);
+ if (rc < 0) {
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) Error in BTS configuration -- cannot bootstrap RSL\n",
+ trx->bts->nr);
+ return rc;
+ }
bootstrap_rsl(trx);
+ }
break;
case S_L_INP_TEI_DN:
LOG_TRX(trx, DLMI, LOGL_ERROR, "Lost E1 %s link\n", e1inp_signtype_name(isd->link_type));
if (isd->link_type == E1INP_SIGN_OML) {
- rate_ctr_inc(&trx->bts->bts_ctrs->ctr[BTS_CTR_BTS_OML_FAIL]);
- all_ts_dispatch_event(trx, TS_EV_OML_DOWN);
+ rate_ctr_inc(rate_ctr_group_get_ctr(trx->bts->bts_ctrs, BTS_CTR_BTS_OML_FAIL));
+ /* ip.access BTS models have a single global A-bis/OML link for all
+ * transceivers, so once it's lost we need to notify them all. */
+ if (is_ipaccess_bts(trx->bts))
+ gsm_bts_all_ts_dispatch(trx->bts, TS_EV_OML_DOWN, NULL);
+ else /* Other BTS models (e.g. Ericsson) have per-TRX OML links */
+ gsm_trx_all_ts_dispatch(trx, TS_EV_OML_DOWN, NULL);
} else if (isd->link_type == E1INP_SIGN_RSL) {
- rate_ctr_inc(&trx->bts->bts_ctrs->ctr[BTS_CTR_BTS_RSL_FAIL]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(trx->bts->bts_ctrs, BTS_CTR_BTS_RSL_FAIL));
acc_ramp_abort(&trx->bts->acc_ramp);
- all_ts_dispatch_event(trx, TS_EV_RSL_DOWN);
- if (trx->nr == 0)
- osmo_timer_del(&trx->bts->cbch_timer);
+ gsm_trx_all_ts_dispatch(trx, TS_EV_RSL_DOWN, NULL);
}
- gsm_bts_mo_reset(trx->bts);
+ gsm_bts_sm_mo_reset(trx->bts->site_mgr);
abis_nm_clear_queue(trx->bts);
break;
@@ -412,105 +476,6 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
return 0;
}
-static int bootstrap_bts(struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
- unsigned int n = 0;
-
- if (!bts->model)
- return -EFAULT;
-
- if (bts->model->start && !bts->model->started) {
- int ret = bts->model->start(bts->network);
- if (ret < 0)
- return ret;
-
- bts->model->started = true;
- }
-
- /* FIXME: What about secondary TRX of a BTS? What about a BTS that has TRX
- * in different bands? Why is 'band' a parameter of the BTS and not of the TRX? */
- switch (bts->band) {
- case GSM_BAND_1800:
- if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) {
- LOGP(DNM, LOGL_ERROR, "GSM1800 channel must be between 512-885.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_1900:
- if (bts->c0->arfcn < 512 || bts->c0->arfcn > 810) {
- LOGP(DNM, LOGL_ERROR, "GSM1900 channel must be between 512-810.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_900:
- if ((bts->c0->arfcn > 124 && bts->c0->arfcn < 955) ||
- bts->c0->arfcn > 1023) {
- LOGP(DNM, LOGL_ERROR, "GSM900 channel must be between 0-124, 955-1023.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_850:
- if (bts->c0->arfcn < 128 || bts->c0->arfcn > 251) {
- LOGP(DNM, LOGL_ERROR, "GSM850 channel must be between 128-251.\n");
- return -EINVAL;
- }
- break;
- default:
- LOGP(DNM, LOGL_ERROR, "Unsupported frequency band.\n");
- return -EINVAL;
- }
-
- /* Verify the physical channel mapping */
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (!trx_has_valid_pchan_config(trx)) {
- LOGP(DNM, LOGL_ERROR, "TRX %u has invalid timeslot "
- "configuration\n", trx->nr);
- return -EINVAL;
- }
- }
-
- /* Control Channel Description is set from vty/config */
-
- /* Indicate R99 MSC in SI3 */
- bts->si_common.chan_desc.mscr = 1;
-
- /* Determine the value of CCCH_CONF. Is TS0/C0 combined? */
- if (bts->c0->ts[0].pchan_from_config != GSM_PCHAN_CCCH) {
- bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
-
- /* Limit reserved block to 2 on combined channel according to
- 3GPP TS 44.018 Table 10.5.2.11.1 */
- if (bts->si_common.chan_desc.bs_ag_blks_res > 2) {
- LOGP(DNM, LOGL_NOTICE, "CCCH is combined with SDCCHs, "
- "reducing BS-AG-BLKS-RES value %d -> 2\n",
- bts->si_common.chan_desc.bs_ag_blks_res);
- bts->si_common.chan_desc.bs_ag_blks_res = 2;
- }
- } else { /* Non-combined TS0/C0 configuration */
- /* There can be additional CCCHs on even timeslot numbers */
- n += (bts->c0->ts[2].pchan_from_config == GSM_PCHAN_CCCH);
- n += (bts->c0->ts[4].pchan_from_config == GSM_PCHAN_CCCH);
- n += (bts->c0->ts[6].pchan_from_config == GSM_PCHAN_CCCH);
- bts->si_common.chan_desc.ccch_conf = (n << 1);
- }
-
- bts->si_common.cell_options.pwrc = 0; /* PWRC not set */
-
- bts->si_common.cell_sel_par.acs = 0;
-
- bts->si_common.ncc_permitted = 0xff;
-
- bts->chan_load_samples_idx = 0;
-
- /* ACC ramping is initialized from vty/config */
-
- /* Initialize the BTS state */
- gsm_bts_mo_reset(bts);
-
- return 0;
-}
-
static int bsc_network_configure(const char *config_file)
{
struct gsm_bts *bts;
@@ -523,8 +488,7 @@ static int bsc_network_configure(const char *config_file)
}
/* start telnet after reading config for vty_get_bind_addr() */
- rc = telnet_init_dynif(tall_bsc_ctx, bsc_gsmnet, vty_get_bind_addr(),
- OSMO_VTY_PORT_NITB_BSC);
+ rc = telnet_init_default(tall_bsc_ctx, bsc_gsmnet, OSMO_VTY_PORT_NITB_BSC);
if (rc < 0)
return rc;
@@ -532,11 +496,12 @@ static int bsc_network_configure(const char *config_file)
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
- rc = bootstrap_bts(bts);
+ rc = gsm_bts_check_cfg(bts);
if (rc < 0) {
- LOGP(DNM, LOGL_FATAL, "Error bootstrapping BTS\n");
+ LOGP(DNM, LOGL_FATAL, "(bts=%u) cannot bootstrap BTS, invalid BTS configuration\n", bts->nr);
return rc;
}
+ bootstrap_bts(bts);
rc = e1_reconfig_bts(bts);
if (rc < 0) {
LOGP(DNM, LOGL_FATAL, "Error enabling E1 input driver\n");
@@ -554,6 +519,11 @@ static int bsc_vty_go_parent(struct vty *vty)
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
+ case MGW_NODE:
+ vty->node = GSMNET_NODE;
+ vty->index = bsc_gsmnet;
+ vty->index_sub = NULL;
+ break;
case BTS_NODE:
vty->node = GSMNET_NODE;
{
@@ -563,6 +533,21 @@ static int bsc_vty_go_parent(struct vty *vty)
vty->index_sub = NULL;
}
break;
+ case POWER_CTRL_NODE:
+ vty->node = BTS_NODE;
+ {
+ const struct gsm_power_ctrl_params *cp = vty->index;
+ struct gsm_bts *bts;
+
+ if (cp->dir == GSM_PWR_CTRL_DIR_UL)
+ bts = container_of(cp, struct gsm_bts, ms_power_ctrl);
+ else
+ bts = container_of(cp, struct gsm_bts, bs_power_ctrl);
+
+ vty->index_sub = &bts->description;
+ vty->index = bts;
+ }
+ break;
case TRX_NODE:
vty->node = BTS_NODE;
{
@@ -578,7 +563,6 @@ static int bsc_vty_go_parent(struct vty *vty)
/* set vty->index correctly ! */
struct gsm_bts_trx_ts *ts = vty->index;
vty->index = ts->trx;
- vty->index_sub = &ts->trx->description;
}
break;
case OML_NODE:
@@ -636,7 +620,9 @@ static struct vty_app_info vty_info = {
.copyright =
"Copyright (C) 2008-2018 Harald Welte, Holger Freyther\r\n"
"Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\r\n"
- "Dieter Spaar, Andreas Eversberg, Sylvain Munaut, Neels Hofmeyr\r\n\r\n"
+ "Dieter Spaar, Andreas Eversberg, Sylvain Munaut, Neels Hofmeyr\r\n"
+ "Copyright (C) 2013-2022 sysmocom - s.f.m.c. GmbH\r\n"
+ "\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n",
@@ -650,30 +636,44 @@ static struct vty_app_info vty_info = {
"This command applies on A-bis RSL link (re)establishment",
[BSC_VTY_ATTR_NEW_LCHAN] = \
"This command applies for newly created lchans",
+ [BSC_VTY_ATTR_VENDOR_SPECIFIC] = \
+ "This command/parameter is BTS vendor specific",
},
.usr_attr_letters = {
[BSC_VTY_ATTR_RESTART_ABIS_OML_LINK] = 'o',
[BSC_VTY_ATTR_RESTART_ABIS_RSL_LINK] = 'r',
[BSC_VTY_ATTR_NEW_LCHAN] = 'l',
+ [BSC_VTY_ATTR_VENDOR_SPECIFIC] = 'v',
},
};
extern int bsc_shutdown_net(struct gsm_network *net);
-static void signal_handler(int signal)
+static void signal_handler(int signum)
{
- fprintf(stdout, "signal %u received\n", signal);
+ fprintf(stdout, "signal %u received\n", signum);
- switch (signal) {
+ switch (signum) {
case SIGINT:
case SIGTERM:
+ /* If SIGTERM was already sent before, just terminate immediately. */
+ if (osmo_select_shutdown_requested())
+ exit(-1);
bsc_shutdown_net(bsc_gsmnet);
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
- sleep(3);
- exit(0);
+ osmo_select_shutdown_request();
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 */
+ /* in case of abort, we want to obtain a talloc report and
+ * then run default SIGABRT handler, who will generate coredump
+ * and abort the process. abort() should do this for us after we
+ * return, but program wouldn't exit if an external SIGABRT is
+ * received.
+ */
+ talloc_report(tall_vty_ctx, stderr);
+ talloc_report_full(tall_bsc_ctx, stderr);
+ signal(SIGABRT, SIG_DFL);
+ raise(SIGABRT);
+ break;
case SIGUSR1:
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_bsc_ctx, stderr);
@@ -800,6 +800,12 @@ static const struct log_info_cat osmo_bsc_categories[] = {
.description = "RESET/ACK on A and Lb interfaces",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
+ [DLOOP] = {
+ .name = "DLOOP",
+ .description = "Control loops",
+ .color = "\033[0;34m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
};
static int filter_fn(const struct log_context *ctx, struct log_target *tar)
@@ -824,7 +830,41 @@ const struct log_info log_info = {
extern void *tall_paging_ctx;
extern void *tall_fle_ctx;
extern void *tall_tqe_ctx;
-extern void *tall_ctr_ctx;
+
+static int bsc_mgw_setup(void)
+{
+ struct mgcp_client *mgcp_client_single;
+ unsigned int pool_members_initalized;
+
+ /* Initialize MGW pool. This initalizes and connects all MGCP clients that are currently configured in
+ * the pool. Adding additional MGCP clients to the pool is possible but the user has to configure and
+ * (re)connect them manually from the VTY. */
+ pool_members_initalized = mgcp_client_pool_connect(bsc_gsmnet->mgw.mgw_pool);
+ if (pool_members_initalized) {
+ LOGP(DNM, LOGL_NOTICE,
+ "MGW pool with %u pool members configured, (ignoring MGW configuration in VTY node 'msc').\n",
+ pool_members_initalized);
+ return 0;
+ }
+
+ /* Initialize and connect a single MGCP client. This MGCP client will appear as the one and only pool
+ * member if there is no MGW pool configured. */
+ LOGP(DNM, LOGL_NOTICE, "No MGW pool configured, using MGW configuration in VTY node 'msc'\n");
+ mgcp_client_single = mgcp_client_init(bsc_gsmnet, bsc_gsmnet->mgw.conf);
+ if (!mgcp_client_single) {
+ LOGP(DNM, LOGL_ERROR, "MGW (single) client initalization failed\n");
+ return -EINVAL;
+ }
+ if (mgcp_client_connect(mgcp_client_single)) {
+ LOGP(DNM, LOGL_ERROR, "MGW (single) connect failed at (%s:%u)\n",
+ bsc_gsmnet->mgw.conf->remote_addr,
+ bsc_gsmnet->mgw.conf->remote_port);
+ return -EINVAL;
+ }
+ mgcp_client_pool_register_single(bsc_gsmnet->mgw.mgw_pool, mgcp_client_single);
+
+ return 0;
+}
int main(int argc, char **argv)
{
@@ -840,13 +880,13 @@ int main(int argc, char **argv)
tall_paging_ctx = talloc_named_const(tall_bsc_ctx, 0, "paging_request");
tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0, "bs11_file_list_entry");
tall_tqe_ctx = talloc_named_const(tall_bsc_ctx, 0, "subch_txq_entry");
- tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
osmo_init_logging2(tall_bsc_ctx, &log_info);
osmo_stats_init(tall_bsc_ctx);
rate_ctr_init(tall_bsc_ctx);
osmo_fsm_set_dealloc_ctx(OTC_SELECT);
+ osmo_fsm_log_timeouts(true);
/* Allocate global gsm_network struct */
rc = bsc_network_alloc();
@@ -856,6 +896,7 @@ int main(int argc, char **argv)
}
bsc_gsmnet->mgw.conf = talloc_zero(bsc_gsmnet, struct mgcp_client_conf);
+ bsc_gsmnet->mgw.mgw_pool = mgcp_client_pool_alloc(bsc_gsmnet);
mgcp_client_conf_init(bsc_gsmnet->mgw.conf);
bts_init();
@@ -883,12 +924,14 @@ int main(int argc, char **argv)
/* seed the PRNG */
srand(time(NULL));
- ts_fsm_init();
lchan_fsm_init();
bsc_subscr_conn_fsm_init();
assignment_fsm_init();
handover_fsm_init();
lb_init();
+ acc_ramp_global_init();
+ paging_global_init();
+ smscb_global_init();
/* Read the config */
rc = bsc_network_configure(config_file);
@@ -897,11 +940,14 @@ int main(int argc, char **argv)
exit(1);
}
+ if (neighbors_check_cfg()) {
+ fprintf(stderr, "Errors in neighbor configuration, check the DHO log. exiting.\n");
+ exit(1);
+ }
+
/* 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);
+ bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, OSMO_CTRL_PORT_NITB_BSC);
if (!bsc_gsmnet->ctrl) {
fprintf(stderr, "Failed to init the control interface. Exiting.\n");
exit(1);
@@ -913,6 +959,19 @@ int main(int argc, char **argv)
exit(1);
}
+ if (bsc_gsmnet->neigh_ctrl.addr) {
+ bsc_gsmnet->neigh_ctrl.handle = neighbor_controlif_setup(bsc_gsmnet);
+ if (!bsc_gsmnet->neigh_ctrl.handle) {
+ fprintf(stderr, "Failed to bind Neighbor Resolution Service. Exiting.\n");
+ exit(1);
+ }
+ rc = neighbor_ctrl_cmds_install(bsc_gsmnet);
+ if (rc < 0) {
+ fprintf(stderr, "Failed to install Neighbor Resolution Service commands. Exiting.\n");
+ exit(1);
+ }
+ }
+
if (rf_ctrl)
osmo_talloc_replace_string(bsc_gsmnet, &bsc_gsmnet->rf_ctrl_name, rf_ctrl);
@@ -934,6 +993,9 @@ int main(int argc, char **argv)
}
}
+ if (bsc_mgw_setup() != 0)
+ exit(1);
+
llist_for_each_entry(msc, &bsc_gsmnet->mscs, entry) {
if (osmo_bsc_msc_init(msc) != 0) {
LOGP(DMSC, LOGL_ERROR, "Failed to start up. Exiting.\n");
@@ -941,15 +1003,6 @@ int main(int argc, char **argv)
}
}
- bsc_gsmnet->mgw.client = mgcp_client_init(bsc_gsmnet, bsc_gsmnet->mgw.conf);
-
- if (mgcp_client_connect(bsc_gsmnet->mgw.client)) {
- LOGP(DNM, LOGL_ERROR, "MGW connect failed at (%s:%u)\n",
- bsc_gsmnet->mgw.conf->remote_addr,
- bsc_gsmnet->mgw.conf->remote_port);
- exit(1);
- }
-
if (osmo_bsc_sigtran_init(&bsc_gsmnet->mscs) != 0) {
LOGP(DNM, LOGL_ERROR, "Failed to initialize sigtran backhaul.\n");
exit(1);
@@ -967,6 +1020,9 @@ int main(int argc, char **argv)
signal(SIGUSR2, &signal_handler);
osmo_init_ignore_signals();
+ update_connection_stats_cb(NULL);
+ chan_counts_sig_init();
+
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {
@@ -975,7 +1031,7 @@ int main(int argc, char **argv)
}
}
- while (1) {
+ while (!osmo_select_shutdown_done()) {
osmo_select_main_ctx(0);
}