/* * Copyright (C) 2024 by sysmocom s.f.m.c. GmbH * * 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 General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include static int verify_lchan_ms_power(struct ctrl_cmd *cmd, const char *value, void *_data) { int ms_power = atoi(cmd->value); if (ms_power < 0 || ms_power > 40) { cmd->reply = "Value is out of range"; return 1; } return 0; } /* power control management: Get lchan's ms power in dBm * format: bts.<0-255>.trx.<0-255>.ts.<0-8>.lchan.<0-8>.ms-power */ static int get_lchan_ms_power(struct ctrl_cmd *cmd, void *data) { struct gsm_lchan *lchan = cmd->node; cmd->reply = talloc_asprintf(cmd, "%u", ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power)); if (!cmd->reply) { cmd->reply = "OOM"; return CTRL_CMD_ERROR; } return CTRL_CMD_REPLY; } /* power control management: Set lchan's ms power in dBm. * For static ms power control it will change the ms tx power. * For dynamic ms power control it will limit the maximum power level. * format: bts.<0-255>.trx.<0-255>.ts.<0-8>.lchan.<0-8>.ms-power * ms power is in range 0..40 */ static int set_lchan_ms_power(struct ctrl_cmd *cmd, void *data) { struct gsm_lchan *lchan = cmd->node; lchan->ms_power = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, atoi(cmd->value)); rsl_chan_ms_power_ctrl(lchan); cmd->reply = "OK"; return CTRL_CMD_REPLY; } CTRL_CMD_DEFINE(lchan_ms_power, "ms-power"); char *lchan_dump_full_ctrl(const void *t, struct gsm_lchan *lchan) { struct in_addr ia; char *interference = ",", *tmsi = "", *ipa_bound = ",,", *ipa_conn = ",,"; if (lchan->interf_dbm != INTERF_DBM_UNKNOWN) { interference = talloc_asprintf(t, "%d,%u", lchan->interf_dbm, lchan->interf_band); if (!interference) return NULL; } if (lchan->conn && lchan->conn->bsub && lchan->conn->bsub->tmsi != GSM_RESERVED_TMSI) { tmsi = talloc_asprintf(t, "0x%08x", lchan->conn->bsub->tmsi); if (!tmsi) return NULL; } if (is_ipa_abisip_bts(lchan->ts->trx->bts) && lchan->abis_ip.bound_ip) { ia.s_addr = htonl(lchan->abis_ip.bound_ip); ipa_bound = talloc_asprintf(t, "%s,%u,%u", inet_ntoa(ia), lchan->abis_ip.bound_port, lchan->abis_ip.conn_id); if (!ipa_bound) return NULL; } if (is_ipa_abisip_bts(lchan->ts->trx->bts) && lchan->abis_ip.connect_ip) { ia.s_addr = htonl(lchan->abis_ip.connect_ip); ipa_conn = talloc_asprintf(t, "%s,%u,0x%02x", inet_ntoa(ia), lchan->abis_ip.connect_port, lchan->abis_ip.speech_mode); if (!ipa_conn) return NULL; } return talloc_asprintf(t, "%u,%u,%u,%u,%s,%u,%s,%s,%u,%u,%s,%s,%s,%s,%s,%s", lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, lchan->nr, gsm_chan_t_name(lchan->type), lchan->conn ? 1 : 0, lchan_state_name(lchan), lchan->fi && lchan->fi->state == LCHAN_ST_BORKEN ? lchan->last_error : "", lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red - lchan->bs_power_db, ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power), interference, gsm48_chan_mode_name(lchan->current_ch_mode_rate.chan_mode), lchan->conn && lchan->conn->bsub && strlen(lchan->conn->bsub->imsi) ? lchan->conn->bsub->imsi : "", tmsi, ipa_bound, ipa_conn ); } /* Return full information about a logical channel. * format: bts.<0-255>.trx.<0-255>.ts.<0-8>.lchan.<0-8>.show.full * result format: ,,,,,,,,,,, * ,,,,,,,, * , */ static int get_lchan_show_full(struct ctrl_cmd *cmd, void *data) { struct gsm_lchan *lchan = cmd->node; cmd->reply = lchan_dump_full_ctrl(cmd, lchan); if (!cmd->reply) { cmd->reply = "OOM"; return CTRL_CMD_ERROR; } return CTRL_CMD_REPLY; } CTRL_CMD_DEFINE_RO(lchan_show_full, "show full"); int bsc_bts_trx_ts_lchan_ctrl_cmds_install(void) { int rc = 0; rc |= ctrl_cmd_install(CTRL_NODE_LCHAN, &cmd_lchan_ms_power); rc |= ctrl_cmd_install(CTRL_NODE_LCHAN, &cmd_lchan_show_full); return rc; }