2013-01-09 16:03:27 +00:00
|
|
|
/*
|
2015-01-31 21:16:00 +00:00
|
|
|
* (C) 2013-2015 by Holger Hans Peter Freyther
|
|
|
|
* (C) 2013-2015 by sysmocom s.f.m.c. GmbH
|
2013-01-09 16:03:27 +00:00
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*
|
|
|
|
*/
|
2014-08-20 21:47:15 +00:00
|
|
|
#include <errno.h>
|
2015-02-10 20:37:16 +00:00
|
|
|
#include <time.h>
|
2013-01-09 16:03:27 +00:00
|
|
|
|
2014-08-20 21:47:15 +00:00
|
|
|
#include <osmocom/ctrl/control_cmd.h>
|
2021-05-17 16:59:58 +00:00
|
|
|
|
|
|
|
#include <osmocom/vty/command.h>
|
2021-06-21 12:47:21 +00:00
|
|
|
#include <osmocom/vty/misc.h>
|
2021-05-17 16:59:58 +00:00
|
|
|
|
2018-03-05 01:09:40 +00:00
|
|
|
#include <osmocom/gsm/gsm48.h>
|
2017-09-04 13:15:32 +00:00
|
|
|
#include <osmocom/bsc/ipaccess.h>
|
|
|
|
#include <osmocom/bsc/gsm_data.h>
|
|
|
|
#include <osmocom/bsc/abis_nm.h>
|
|
|
|
#include <osmocom/bsc/debug.h>
|
|
|
|
#include <osmocom/bsc/chan_alloc.h>
|
|
|
|
#include <osmocom/bsc/osmo_bsc_rf.h>
|
|
|
|
#include <osmocom/bsc/bsc_msc_data.h>
|
2020-07-15 18:53:16 +00:00
|
|
|
#include <osmocom/bsc/bts.h>
|
2013-01-09 16:03:27 +00:00
|
|
|
|
2021-05-17 16:59:58 +00:00
|
|
|
static int verify_net_apply_config_file(struct ctrl_cmd *cmd, const char *value, void *_data)
|
|
|
|
{
|
|
|
|
FILE *cfile;
|
|
|
|
|
|
|
|
if (!cmd->value || cmd->value[0] == '\0')
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
cfile = fopen(cmd->value, "r");
|
|
|
|
if (!cfile)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
fclose(cfile);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int set_net_apply_config_file(struct ctrl_cmd *cmd, void *_data)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
FILE *cfile;
|
|
|
|
unsigned cmd_ret = CTRL_CMD_ERROR;
|
|
|
|
|
|
|
|
LOGP(DCTRL, LOGL_NOTICE, "Applying VTY snippet from %s...\n", cmd->value);
|
|
|
|
cfile = fopen(cmd->value, "r");
|
|
|
|
if (!cfile) {
|
|
|
|
LOGP(DCTRL, LOGL_NOTICE, "Applying VTY snippet from %s: fopen() failed: %d\n",
|
|
|
|
cmd->value, errno);
|
|
|
|
cmd->reply = "NoFile";
|
2021-05-25 09:48:17 +00:00
|
|
|
return cmd_ret;
|
2021-05-17 16:59:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = vty_read_config_filep(cfile, NULL);
|
|
|
|
LOGP(DCTRL, LOGL_NOTICE, "Applying VTY snippet from %s returned %d\n", cmd->value, rc);
|
|
|
|
if (rc) {
|
|
|
|
cmd->reply = talloc_asprintf(cmd, "ParseError=%d", rc);
|
|
|
|
if (!cmd->reply)
|
|
|
|
cmd->reply = "OOM";
|
|
|
|
goto close_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd->reply = "OK";
|
|
|
|
cmd_ret = CTRL_CMD_REPLY;
|
|
|
|
close_ret:
|
|
|
|
fclose(cfile);
|
|
|
|
return cmd_ret;
|
|
|
|
}
|
|
|
|
CTRL_CMD_DEFINE_WO(net_apply_config_file, "apply-config-file");
|
|
|
|
|
2021-06-21 12:47:21 +00:00
|
|
|
static int verify_net_write_config_file(struct ctrl_cmd *cmd, const char *value, void *_data)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int set_net_write_config_file(struct ctrl_cmd *cmd, void *_data)
|
|
|
|
{
|
|
|
|
const char *cfile_name;
|
|
|
|
unsigned cmd_ret = CTRL_CMD_ERROR;
|
|
|
|
|
|
|
|
if (strcmp(cmd->value, "overwrite"))
|
|
|
|
host_config_set(cmd->value);
|
|
|
|
|
|
|
|
cfile_name = host_config_file();
|
|
|
|
|
|
|
|
LOGP(DCTRL, LOGL_NOTICE, "Writing VTY config to file %s...\n", cfile_name);
|
|
|
|
if (osmo_vty_write_config_file(cfile_name) < 0)
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
cmd->reply = "OK";
|
|
|
|
cmd_ret = CTRL_CMD_REPLY;
|
|
|
|
ret:
|
|
|
|
return cmd_ret;
|
|
|
|
}
|
|
|
|
CTRL_CMD_DEFINE_WO(net_write_config_file, "write-config-file");
|
|
|
|
|
2018-03-05 01:09:40 +00:00
|
|
|
CTRL_CMD_DEFINE(net_mcc, "mcc");
|
|
|
|
static int get_net_mcc(struct ctrl_cmd *cmd, void *_data)
|
|
|
|
{
|
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
cmd->reply = talloc_asprintf(cmd, "%s", osmo_mcc_name(net->plmn.mcc));
|
|
|
|
if (!cmd->reply) {
|
|
|
|
cmd->reply = "OOM";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
static int set_net_mcc(struct ctrl_cmd *cmd, void *_data)
|
|
|
|
{
|
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
uint16_t mcc;
|
|
|
|
if (osmo_mcc_from_str(cmd->value, &mcc))
|
|
|
|
return -1;
|
|
|
|
net->plmn.mcc = mcc;
|
|
|
|
return get_net_mcc(cmd, _data);
|
|
|
|
}
|
|
|
|
static int verify_net_mcc(struct ctrl_cmd *cmd, const char *value, void *_data)
|
|
|
|
{
|
|
|
|
if (osmo_mcc_from_str(value, NULL))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CTRL_CMD_DEFINE(net_mnc, "mnc");
|
|
|
|
static int get_net_mnc(struct ctrl_cmd *cmd, void *_data)
|
|
|
|
{
|
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
cmd->reply = talloc_asprintf(cmd, "%s", osmo_mnc_name(net->plmn.mnc, net->plmn.mnc_3_digits));
|
|
|
|
if (!cmd->reply) {
|
|
|
|
cmd->reply = "OOM";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
static int set_net_mnc(struct ctrl_cmd *cmd, void *_data)
|
|
|
|
{
|
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
struct osmo_plmn_id plmn = net->plmn;
|
|
|
|
if (osmo_mnc_from_str(cmd->value, &plmn.mnc, &plmn.mnc_3_digits)) {
|
|
|
|
cmd->reply = "Error while decoding MNC";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
net->plmn = plmn;
|
|
|
|
return get_net_mnc(cmd, _data);
|
|
|
|
}
|
|
|
|
static int verify_net_mnc(struct ctrl_cmd *cmd, const char *value, void *_data)
|
|
|
|
{
|
|
|
|
if (osmo_mnc_from_str(value, NULL, NULL))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
2013-01-09 16:03:27 +00:00
|
|
|
|
2013-01-09 16:30:11 +00:00
|
|
|
static int set_net_apply_config(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
struct gsm_bts *bts;
|
|
|
|
|
|
|
|
llist_for_each_entry(bts, &net->bts_list, list) {
|
|
|
|
if (!is_ipaccess_bts(bts))
|
|
|
|
continue;
|
|
|
|
|
2016-03-16 14:27:38 +00:00
|
|
|
/*
|
|
|
|
* The ip.access nanoBTS seems to be unrelaible on BSSGP
|
|
|
|
* so let's us just reboot it. For the sysmoBTS we can just
|
|
|
|
* restart the process as all state is gone.
|
|
|
|
*/
|
2021-04-04 18:39:16 +00:00
|
|
|
if (!is_osmobts(bts) && strcmp(cmd->value, "restart") == 0) {
|
2016-03-16 14:27:38 +00:00
|
|
|
struct gsm_bts_trx *trx;
|
|
|
|
llist_for_each_entry_reverse(trx, &bts->trx_list, list)
|
|
|
|
abis_nm_ipaccess_restart(trx);
|
|
|
|
} else
|
2019-01-02 14:28:17 +00:00
|
|
|
ipaccess_drop_oml(bts, "ctrl net.apply-configuration");
|
2013-01-09 16:30:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cmd->reply = "Tried to drop the BTS";
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:37:55 +00:00
|
|
|
CTRL_CMD_DEFINE_WO_NOVRF(net_apply_config, "apply-configuration");
|
2013-01-09 16:30:11 +00:00
|
|
|
|
2014-03-04 16:16:58 +00:00
|
|
|
static int verify_net_mcc_mnc_apply(struct ctrl_cmd *cmd, const char *value, void *d)
|
|
|
|
{
|
|
|
|
char *tmp, *saveptr, *mcc, *mnc;
|
2018-03-05 01:09:40 +00:00
|
|
|
int rc = 0;
|
2014-03-04 16:16:58 +00:00
|
|
|
|
|
|
|
tmp = talloc_strdup(cmd, value);
|
|
|
|
if (!tmp)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
mcc = strtok_r(tmp, ",", &saveptr);
|
|
|
|
mnc = strtok_r(NULL, ",", &saveptr);
|
|
|
|
|
2018-03-05 01:09:40 +00:00
|
|
|
if (osmo_mcc_from_str(mcc, NULL) || osmo_mnc_from_str(mnc, NULL, NULL))
|
|
|
|
rc = -1;
|
|
|
|
|
|
|
|
talloc_free(tmp);
|
|
|
|
return rc;
|
2014-03-04 16:16:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int set_net_mcc_mnc_apply(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
char *tmp, *saveptr, *mcc_str, *mnc_str;
|
2018-03-05 01:09:40 +00:00
|
|
|
struct osmo_plmn_id plmn;
|
2014-03-04 16:16:58 +00:00
|
|
|
|
|
|
|
tmp = talloc_strdup(cmd, cmd->value);
|
|
|
|
if (!tmp)
|
|
|
|
goto oom;
|
|
|
|
|
|
|
|
mcc_str = strtok_r(tmp, ",", &saveptr);
|
|
|
|
mnc_str = strtok_r(NULL, ",", &saveptr);
|
|
|
|
|
2018-03-05 01:09:40 +00:00
|
|
|
if (osmo_mcc_from_str(mcc_str, &plmn.mcc)) {
|
|
|
|
cmd->reply = "Error while decoding MCC";
|
2018-04-11 10:41:44 +00:00
|
|
|
talloc_free(tmp);
|
2018-03-05 01:09:40 +00:00
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (osmo_mnc_from_str(mnc_str, &plmn.mnc, &plmn.mnc_3_digits)) {
|
|
|
|
cmd->reply = "Error while decoding MNC";
|
2018-04-11 10:41:44 +00:00
|
|
|
talloc_free(tmp);
|
2018-03-05 01:09:40 +00:00
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
2014-03-04 16:16:58 +00:00
|
|
|
|
|
|
|
talloc_free(tmp);
|
|
|
|
|
2018-03-05 01:09:40 +00:00
|
|
|
if (!osmo_plmn_cmp(&net->plmn, &plmn)) {
|
2014-03-04 16:16:58 +00:00
|
|
|
cmd->reply = "Nothing changed";
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
|
2018-03-05 01:09:40 +00:00
|
|
|
net->plmn = plmn;
|
2014-03-04 16:16:58 +00:00
|
|
|
|
|
|
|
return set_net_apply_config(cmd, data);
|
|
|
|
|
|
|
|
oom:
|
|
|
|
cmd->reply = "OOM";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
2017-01-11 17:37:55 +00:00
|
|
|
CTRL_CMD_DEFINE_WO(net_mcc_mnc_apply, "mcc-mnc-apply");
|
2014-03-04 16:16:58 +00:00
|
|
|
|
2014-11-10 10:41:03 +00:00
|
|
|
/* BTS related commands below */
|
|
|
|
CTRL_CMD_DEFINE_RANGE(bts_lac, "location-area-code", struct gsm_bts, location_area_code, 0, 65535);
|
2014-11-21 09:54:42 +00:00
|
|
|
CTRL_CMD_DEFINE_RANGE(bts_ci, "cell-identity", struct gsm_bts, cell_identity, 0, 65535);
|
2014-11-10 10:41:03 +00:00
|
|
|
|
2014-11-21 09:20:29 +00:00
|
|
|
static int set_bts_apply_config(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
struct gsm_bts *bts = cmd->node;
|
|
|
|
|
|
|
|
if (!is_ipaccess_bts(bts)) {
|
|
|
|
cmd->reply = "BTS is not IP based";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
2019-01-02 14:28:17 +00:00
|
|
|
ipaccess_drop_oml(bts, "ctrl bts.apply-configuration");
|
2014-11-21 09:20:29 +00:00
|
|
|
cmd->reply = "Tried to drop the BTS";
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:37:55 +00:00
|
|
|
CTRL_CMD_DEFINE_WO_NOVRF(bts_apply_config, "apply-configuration");
|
2014-11-21 10:18:45 +00:00
|
|
|
|
|
|
|
static int set_bts_si(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
struct gsm_bts *bts = cmd->node;
|
2015-05-30 18:40:54 +00:00
|
|
|
int rc;
|
2014-11-21 10:18:45 +00:00
|
|
|
|
2015-05-30 18:40:54 +00:00
|
|
|
rc = gsm_bts_set_system_infos(bts);
|
|
|
|
if (rc != 0) {
|
|
|
|
cmd->reply = "Failed to generate SI";
|
|
|
|
return CTRL_CMD_ERROR;
|
2014-11-21 10:18:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cmd->reply = "Generated new System Information";
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
2017-01-11 17:37:55 +00:00
|
|
|
CTRL_CMD_DEFINE_WO_NOVRF(bts_si, "send-new-system-informations");
|
2014-12-05 11:03:24 +00:00
|
|
|
|
|
|
|
static int get_bts_chan_load(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct pchan_load pl;
|
|
|
|
struct gsm_bts *bts;
|
|
|
|
const char *space = "";
|
|
|
|
|
|
|
|
bts = cmd->node;
|
|
|
|
memset(&pl, 0, sizeof(pl));
|
2016-09-25 15:01:20 +00:00
|
|
|
bts_chan_load(&pl, bts);
|
2014-12-05 11:03:24 +00:00
|
|
|
|
|
|
|
cmd->reply = talloc_strdup(cmd, "");
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pl.pchan); ++i) {
|
|
|
|
const struct load_counter *lc = &pl.pchan[i];
|
|
|
|
|
|
|
|
/* These can never have user load */
|
|
|
|
if (i == GSM_PCHAN_NONE)
|
|
|
|
continue;
|
|
|
|
if (i == GSM_PCHAN_CCCH)
|
|
|
|
continue;
|
|
|
|
if (i == GSM_PCHAN_PDCH)
|
|
|
|
continue;
|
2015-01-31 18:42:42 +00:00
|
|
|
if (i == GSM_PCHAN_UNKNOWN)
|
|
|
|
continue;
|
2014-12-05 11:03:24 +00:00
|
|
|
|
|
|
|
cmd->reply = talloc_asprintf_append(cmd->reply,
|
|
|
|
"%s%s,%u,%u",
|
|
|
|
space, gsm_pchan_name(i), lc->used, lc->total);
|
|
|
|
if (!cmd->reply)
|
|
|
|
goto error;
|
|
|
|
space = " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
|
|
|
|
error:
|
|
|
|
cmd->reply = "Memory allocation failure";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:37:55 +00:00
|
|
|
CTRL_CMD_DEFINE_RO(bts_chan_load, "channel-load");
|
2014-12-05 13:44:21 +00:00
|
|
|
|
|
|
|
static int get_bts_oml_conn(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
2017-10-09 15:12:53 +00:00
|
|
|
const struct gsm_bts *bts = cmd->node;
|
|
|
|
|
|
|
|
cmd->reply = get_model_oml_status(bts);
|
2014-12-05 13:44:21 +00:00
|
|
|
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:37:55 +00:00
|
|
|
CTRL_CMD_DEFINE_RO(bts_oml_conn, "oml-connection-state");
|
2014-12-05 13:44:21 +00:00
|
|
|
|
2017-10-10 12:50:35 +00:00
|
|
|
static int get_bts_oml_up(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
const struct gsm_bts *bts = cmd->node;
|
|
|
|
|
|
|
|
cmd->reply = talloc_asprintf(cmd, "%llu", bts_uptime(bts));
|
|
|
|
if (!cmd->reply) {
|
|
|
|
cmd->reply = "OOM";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
CTRL_CMD_DEFINE_RO(bts_oml_up, "oml-uptime");
|
|
|
|
|
2015-01-31 21:16:00 +00:00
|
|
|
static int verify_bts_gprs_mode(struct ctrl_cmd *cmd, const char *value, void *_data)
|
|
|
|
{
|
|
|
|
int valid;
|
|
|
|
enum bts_gprs_mode mode;
|
|
|
|
struct gsm_bts *bts = cmd->node;
|
|
|
|
|
|
|
|
mode = bts_gprs_mode_parse(value, &valid);
|
|
|
|
if (!valid) {
|
|
|
|
cmd->reply = "Mode is not known";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bts_gprs_mode_is_compat(bts, mode)) {
|
|
|
|
cmd->reply = "bts does not support this mode";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_bts_gprs_mode(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
struct gsm_bts *bts = cmd->node;
|
|
|
|
|
|
|
|
cmd->reply = talloc_strdup(cmd, bts_gprs_mode_name(bts->gprs.mode));
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_bts_gprs_mode(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
struct gsm_bts *bts = cmd->node;
|
|
|
|
|
|
|
|
bts->gprs.mode = bts_gprs_mode_parse(cmd->value, NULL);
|
|
|
|
return get_bts_gprs_mode(cmd, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
CTRL_CMD_DEFINE(bts_gprs_mode, "gprs-mode");
|
|
|
|
|
2015-02-10 20:37:16 +00:00
|
|
|
static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
const char *oper, *admin, *policy;
|
|
|
|
struct gsm_bts *bts = cmd->node;
|
|
|
|
|
|
|
|
if (!bts) {
|
|
|
|
cmd->reply = "bts not found.";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
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(cmd, "%s,%s,%s", oper, admin, policy);
|
|
|
|
if (!cmd->reply) {
|
|
|
|
cmd->reply = "OOM.";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
CTRL_CMD_DEFINE_RO(bts_rf_state, "rf_state");
|
|
|
|
|
|
|
|
static int get_net_rf_lock(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
2015-02-10 22:03:25 +00:00
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
struct gsm_bts *bts;
|
|
|
|
const char *policy_name;
|
|
|
|
|
2020-05-26 10:41:18 +00:00
|
|
|
policy_name = osmo_bsc_rf_get_policy_name(net->rf_ctrl->policy);
|
2015-02-10 22:03:25 +00:00
|
|
|
|
|
|
|
llist_for_each_entry(bts, &net->bts_list, list) {
|
|
|
|
struct gsm_bts_trx *trx;
|
|
|
|
|
|
|
|
/* Exclude the BTS from the global lock */
|
|
|
|
if (bts->excl_from_rf_lock)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
llist_for_each_entry(trx, &bts->trx_list, list) {
|
|
|
|
if (trx->mo.nm_state.availability == NM_AVSTATE_OK &&
|
|
|
|
trx->mo.nm_state.operational != NM_OPSTATE_DISABLED) {
|
|
|
|
cmd->reply = talloc_asprintf(cmd,
|
|
|
|
"state=on,policy=%s,bts=%u,trx=%u",
|
|
|
|
policy_name, bts->nr, trx->nr);
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd->reply = talloc_asprintf(cmd, "state=off,policy=%s",
|
|
|
|
policy_name);
|
|
|
|
return CTRL_CMD_REPLY;
|
2015-02-10 20:37:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define TIME_FORMAT_RFC2822 "%a, %d %b %Y %T %z"
|
|
|
|
|
|
|
|
static int set_net_rf_lock(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
int locked = atoi(cmd->value);
|
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
time_t now = time(NULL);
|
|
|
|
char now_buf[64];
|
|
|
|
struct osmo_bsc_rf *rf;
|
|
|
|
|
|
|
|
if (!net) {
|
|
|
|
cmd->reply = "net not found.";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
2020-05-26 10:41:18 +00:00
|
|
|
rf = net->rf_ctrl;
|
2015-02-10 20:37:16 +00:00
|
|
|
|
|
|
|
if (!rf) {
|
|
|
|
cmd->reply = "RF Ctrl is not enabled in the BSC Configuration";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
talloc_free(rf->last_rf_lock_ctrl_command);
|
|
|
|
strftime(now_buf, sizeof(now_buf), TIME_FORMAT_RFC2822, gmtime(&now));
|
|
|
|
rf->last_rf_lock_ctrl_command =
|
|
|
|
talloc_asprintf(rf, "rf_locked %u (%s)", locked, now_buf);
|
|
|
|
|
|
|
|
osmo_bsc_rf_schedule_lock(rf, locked == 1 ? '0' : '1');
|
|
|
|
|
|
|
|
cmd->reply = talloc_asprintf(cmd, "%u", locked);
|
|
|
|
if (!cmd->reply) {
|
|
|
|
cmd->reply = "OOM.";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int verify_net_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
|
|
|
|
{
|
|
|
|
int locked = atoi(cmd->value);
|
|
|
|
|
|
|
|
if ((locked != 0) && (locked != 1))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
CTRL_CMD_DEFINE(net_rf_lock, "rf_locked");
|
2015-01-31 21:16:00 +00:00
|
|
|
|
2015-02-10 20:55:37 +00:00
|
|
|
static int get_net_bts_num(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
struct gsm_network *net = cmd->node;
|
|
|
|
|
|
|
|
cmd->reply = talloc_asprintf(cmd, "%u", net->num_bts);
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
CTRL_CMD_DEFINE_RO(net_bts_num, "number-of-bts");
|
|
|
|
|
2014-03-23 10:17:27 +00:00
|
|
|
/* TRX related commands below here */
|
|
|
|
CTRL_HELPER_GET_INT(trx_max_power, struct gsm_bts_trx, max_power_red);
|
|
|
|
static int verify_trx_max_power(struct ctrl_cmd *cmd, const char *value, void *_data)
|
|
|
|
{
|
|
|
|
int tmp = atoi(value);
|
|
|
|
|
|
|
|
if (tmp < 0 || tmp > 22) {
|
|
|
|
cmd->reply = "Value must be between 0 and 22";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp & 1) {
|
|
|
|
cmd->reply = "Value must be even";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2013-01-09 18:55:04 +00:00
|
|
|
CTRL_CMD_DEFINE_RANGE(trx_arfcn, "arfcn", struct gsm_bts_trx, arfcn, 0, 1023);
|
2014-03-26 13:24:42 +00:00
|
|
|
|
|
|
|
static int set_trx_max_power(struct ctrl_cmd *cmd, void *_data)
|
|
|
|
{
|
|
|
|
struct gsm_bts_trx *trx = cmd->node;
|
|
|
|
int old_power;
|
|
|
|
|
|
|
|
/* remember the old value, set the new one */
|
|
|
|
old_power = trx->max_power_red;
|
|
|
|
trx->max_power_red = atoi(cmd->value);
|
|
|
|
|
|
|
|
/* Maybe update the value */
|
|
|
|
if (old_power != trx->max_power_red) {
|
|
|
|
LOGP(DCTRL, LOGL_NOTICE,
|
|
|
|
"%s updating max_pwr_red(%d)\n",
|
|
|
|
gsm_trx_name(trx), trx->max_power_red);
|
|
|
|
abis_nm_update_max_power_red(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
return get_trx_max_power(cmd, _data);
|
|
|
|
}
|
2014-03-23 10:17:27 +00:00
|
|
|
CTRL_CMD_DEFINE(trx_max_power, "max-power-reduction");
|
|
|
|
|
power_control: implement BCCH carrier power reduction operation
The BCCH carrier (sometimes called C0) of a BTS shall maintain
discontinuous Downlink transmission at full power in order to
stay 'visible' to the mobile stations. Because of that, early
versions of 3GPP TS 45.008 prohibited BS power reduction on C0.
However, starting from version 13.0.0 (2015-11) there is a feature
called 'BCCH carrier power reduction operation'. This is a special
mode of operation, where the variation of RF level for some
timeslots is relaxed for the purpose of energy saving.
In BCCH carrier power reduction operation, for timeslots on the
C0 carrier, except timeslots carrying BCCH/CCCH, the output power
may be lower than the output power used for timeslots carrying
BCCH/CCCH. In this case the maximum allowed difference in output
power actually transmitted by the BTS is 6 dB.
Introduce a VTY command to turn on and off the BCCH carrier power
reduction operation. Also introduce a CTRL command. On the
A-bis/RSL, abuse the BS POWER CONTROL message by setting
the Channel Number IE to 0x80 (RSL_CHAN_BCCH).
Currently, only osmo-bts-trx is supported. A value greater than
zero makes it reduce the power on *inactive* timeslots of the
BCCH carrier. Sending zero disables the BCCH power reduction
mode completely.
For more details, see 3GPP TS 45.008, section 7.1, and 3GPP TR 45.926.
Change-Id: I047fce33d4d3e4c569dd006ba17858467a2f4783
Related: SYS#4919
2021-06-21 19:55:46 +00:00
|
|
|
static int verify_bts_c0_power_red(struct ctrl_cmd *cmd, const char *value, void *_data)
|
|
|
|
{
|
|
|
|
const int red = atoi(value);
|
|
|
|
|
|
|
|
if (red < 0 || red > 6) {
|
|
|
|
cmd->reply = "Value is out of range";
|
|
|
|
return 1;
|
|
|
|
} else if (red % 2 != 0) {
|
|
|
|
cmd->reply = "Value must be even";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_bts_c0_power_red(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
const struct gsm_bts *bts = cmd->node;
|
|
|
|
|
|
|
|
cmd->reply = talloc_asprintf(cmd, "%u", bts->c0_max_power_red_db);
|
|
|
|
if (!cmd->reply) {
|
|
|
|
cmd->reply = "OOM.";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CTRL_CMD_REPLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_bts_c0_power_red(struct ctrl_cmd *cmd, void *data)
|
|
|
|
{
|
|
|
|
struct gsm_bts *bts = cmd->node;
|
|
|
|
const int red = atoi(cmd->value);
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = gsm_bts_set_c0_power_red(bts, red);
|
|
|
|
if (rc == -ENOTSUP) {
|
|
|
|
cmd->reply = "BCCH carrier power reduction is not supported";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
} else if (rc != 0) {
|
|
|
|
cmd->reply = "Failed to enable BCCH carrier power reduction";
|
|
|
|
return CTRL_CMD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return get_bts_c0_power_red(cmd, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
CTRL_CMD_DEFINE(bts_c0_power_red, "c0-power-reduction");
|
|
|
|
|
2013-01-09 16:03:27 +00:00
|
|
|
int bsc_base_ctrl_cmds_install(void)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
2021-05-17 16:59:58 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_apply_config_file);
|
2021-06-21 12:47:21 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_write_config_file);
|
2013-01-09 16:03:27 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mnc);
|
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc);
|
2013-01-09 16:30:11 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_apply_config);
|
2014-03-04 16:16:58 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc_mnc_apply);
|
2015-02-10 20:37:16 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_rf_lock);
|
2015-02-10 20:55:37 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_bts_num);
|
2013-01-09 16:03:27 +00:00
|
|
|
|
2014-11-10 10:41:03 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_lac);
|
2014-11-21 09:54:42 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_ci);
|
2014-11-21 09:20:29 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_apply_config);
|
2014-11-21 10:18:45 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_si);
|
2014-12-05 11:03:24 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_chan_load);
|
2014-12-05 13:44:21 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_oml_conn);
|
2017-10-10 12:50:35 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_oml_up);
|
2015-01-31 21:16:00 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_gprs_mode);
|
2015-02-10 20:37:16 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_rf_state);
|
power_control: implement BCCH carrier power reduction operation
The BCCH carrier (sometimes called C0) of a BTS shall maintain
discontinuous Downlink transmission at full power in order to
stay 'visible' to the mobile stations. Because of that, early
versions of 3GPP TS 45.008 prohibited BS power reduction on C0.
However, starting from version 13.0.0 (2015-11) there is a feature
called 'BCCH carrier power reduction operation'. This is a special
mode of operation, where the variation of RF level for some
timeslots is relaxed for the purpose of energy saving.
In BCCH carrier power reduction operation, for timeslots on the
C0 carrier, except timeslots carrying BCCH/CCCH, the output power
may be lower than the output power used for timeslots carrying
BCCH/CCCH. In this case the maximum allowed difference in output
power actually transmitted by the BTS is 6 dB.
Introduce a VTY command to turn on and off the BCCH carrier power
reduction operation. Also introduce a CTRL command. On the
A-bis/RSL, abuse the BS POWER CONTROL message by setting
the Channel Number IE to 0x80 (RSL_CHAN_BCCH).
Currently, only osmo-bts-trx is supported. A value greater than
zero makes it reduce the power on *inactive* timeslots of the
BCCH carrier. Sending zero disables the BCCH power reduction
mode completely.
For more details, see 3GPP TS 45.008, section 7.1, and 3GPP TR 45.926.
Change-Id: I047fce33d4d3e4c569dd006ba17858467a2f4783
Related: SYS#4919
2021-06-21 19:55:46 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_c0_power_red);
|
2014-11-10 10:41:03 +00:00
|
|
|
|
2014-03-23 10:17:27 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_max_power);
|
2013-01-09 18:55:04 +00:00
|
|
|
rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_arfcn);
|
|
|
|
|
2013-01-09 16:03:27 +00:00
|
|
|
return rc;
|
|
|
|
}
|