2010-03-04 09:39:50 +00:00
|
|
|
/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
|
2008-12-25 23:28:35 +00:00
|
|
|
*
|
2008-12-23 20:25:15 +00:00
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
2011-01-01 14:25:50 +00:00
|
|
|
* 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
|
2008-12-23 20:25:15 +00:00
|
|
|
* (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
|
2011-01-01 14:25:50 +00:00
|
|
|
* GNU Affero General Public License for more details.
|
2008-12-23 20:25:15 +00:00
|
|
|
*
|
2011-01-01 14:25:50 +00:00
|
|
|
* 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/>.
|
2008-12-23 20:25:15 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2009-02-24 22:36:40 +00:00
|
|
|
#include <stdio.h>
|
2008-12-23 20:25:15 +00:00
|
|
|
#include <string.h>
|
2009-06-20 16:15:19 +00:00
|
|
|
#include <errno.h>
|
2009-08-08 14:12:58 +00:00
|
|
|
#include <ctype.h>
|
2016-05-11 10:45:13 +00:00
|
|
|
#include <stdbool.h>
|
2010-03-14 07:37:43 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
|
2011-03-22 15:47:59 +00:00
|
|
|
#include <osmocom/core/linuxlist.h>
|
|
|
|
#include <osmocom/core/talloc.h>
|
|
|
|
#include <osmocom/gsm/gsm_utils.h>
|
2011-05-23 18:30:39 +00:00
|
|
|
#include <osmocom/gsm/abis_nm.h>
|
2011-03-22 15:47:59 +00:00
|
|
|
#include <osmocom/core/statistics.h>
|
2016-05-11 10:45:13 +00:00
|
|
|
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
2008-12-23 20:25:15 +00:00
|
|
|
|
2010-06-28 10:20:22 +00:00
|
|
|
#include <openbsc/gsm_data.h>
|
2010-09-15 14:29:25 +00:00
|
|
|
#include <openbsc/osmo_msc_data.h>
|
2010-06-28 10:20:22 +00:00
|
|
|
#include <openbsc/abis_nm.h>
|
|
|
|
|
2009-06-29 13:19:38 +00:00
|
|
|
void *tall_bsc_ctx;
|
|
|
|
|
2010-01-10 17:01:52 +00:00
|
|
|
static LLIST_HEAD(bts_models);
|
|
|
|
|
2011-04-18 15:04:00 +00:00
|
|
|
void set_ts_e1link(struct gsm_bts_trx_ts *ts, uint8_t e1_nr,
|
|
|
|
uint8_t e1_ts, uint8_t e1_ts_ss)
|
2009-02-10 17:33:56 +00:00
|
|
|
{
|
|
|
|
ts->e1_link.e1_nr = e1_nr;
|
|
|
|
ts->e1_link.e1_ts = e1_ts;
|
|
|
|
ts->e1_link.e1_ts_ss = e1_ts_ss;
|
|
|
|
}
|
|
|
|
|
2010-01-10 17:01:52 +00:00
|
|
|
static struct gsm_bts_model *bts_model_find(enum gsm_bts_type type)
|
|
|
|
{
|
|
|
|
struct gsm_bts_model *model;
|
|
|
|
|
|
|
|
llist_for_each_entry(model, &bts_models, list) {
|
|
|
|
if (model->type == type)
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gsm_bts_model_register(struct gsm_bts_model *model)
|
|
|
|
{
|
|
|
|
if (bts_model_find(model->type))
|
|
|
|
return -EEXIST;
|
|
|
|
|
2011-05-23 18:30:39 +00:00
|
|
|
tlv_def_patch(&model->nm_att_tlvdef, &abis_nm_att_tlvdef);
|
2010-01-10 17:01:52 +00:00
|
|
|
llist_add_tail(&model->list, &bts_models);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-14 21:33:02 +00:00
|
|
|
/* Get reference to a neighbor cell on a given BCCH ARFCN */
|
2009-12-14 23:21:31 +00:00
|
|
|
struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
|
2011-04-18 15:04:00 +00:00
|
|
|
uint16_t arfcn, uint8_t bsic)
|
2009-12-14 21:33:02 +00:00
|
|
|
{
|
|
|
|
struct gsm_bts *neigh;
|
|
|
|
/* FIXME: use some better heuristics here to determine which cell
|
|
|
|
* using this ARFCN really is closest to the target cell. For
|
|
|
|
* now we simply assume that each ARFCN will only be used by one
|
|
|
|
* cell */
|
|
|
|
|
|
|
|
llist_for_each_entry(neigh, &bts->network->bts_list, list) {
|
2009-12-14 23:21:31 +00:00
|
|
|
if (neigh->c0->arfcn == arfcn &&
|
|
|
|
neigh->bsic == bsic)
|
2009-12-14 21:33:02 +00:00
|
|
|
return neigh;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 11:02:12 +00:00
|
|
|
const struct value_string bts_type_names[_NUM_GSM_BTS_TYPE+1] = {
|
2010-03-25 03:45:30 +00:00
|
|
|
{ GSM_BTS_TYPE_UNKNOWN, "unknown" },
|
|
|
|
{ GSM_BTS_TYPE_BS11, "bs11" },
|
|
|
|
{ GSM_BTS_TYPE_NANOBTS, "nanobts" },
|
2011-02-11 17:36:18 +00:00
|
|
|
{ GSM_BTS_TYPE_RBS2000, "rbs2000" },
|
2011-07-27 22:01:50 +00:00
|
|
|
{ GSM_BTS_TYPE_NOKIA_SITE, "nokia_site" },
|
2012-07-02 17:51:55 +00:00
|
|
|
{ GSM_BTS_TYPE_OSMO_SYSMO, "sysmobts" },
|
2010-03-25 03:45:30 +00:00
|
|
|
{ 0, NULL }
|
2009-03-10 12:15:10 +00:00
|
|
|
};
|
|
|
|
|
2012-08-17 11:02:12 +00:00
|
|
|
const struct value_string bts_type_descs[_NUM_GSM_BTS_TYPE+1] = {
|
|
|
|
{ GSM_BTS_TYPE_UNKNOWN, "Unknown BTS Type" },
|
|
|
|
{ GSM_BTS_TYPE_BS11, "Siemens BTS (BS-11 or compatible)" },
|
|
|
|
{ GSM_BTS_TYPE_NANOBTS, "ip.access nanoBTS or compatible" },
|
|
|
|
{ GSM_BTS_TYPE_RBS2000, "Ericsson RBS2000 Series" },
|
|
|
|
{ GSM_BTS_TYPE_NOKIA_SITE, "Nokia {Metro,Ultra,In}Site" },
|
|
|
|
{ GSM_BTS_TYPE_OSMO_SYSMO, "sysmocom sysmoBTS" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2009-08-08 13:38:29 +00:00
|
|
|
enum gsm_bts_type parse_btstype(const char *arg)
|
2009-03-10 12:15:10 +00:00
|
|
|
{
|
2012-08-17 11:02:12 +00:00
|
|
|
return get_string_value(bts_type_names, arg);
|
2009-03-10 12:15:10 +00:00
|
|
|
}
|
|
|
|
|
2009-06-12 15:39:38 +00:00
|
|
|
const char *btstype2str(enum gsm_bts_type type)
|
2009-03-10 12:15:10 +00:00
|
|
|
{
|
2012-08-17 11:02:12 +00:00
|
|
|
return get_value_string(bts_type_names, type);
|
2009-03-10 12:15:10 +00:00
|
|
|
}
|
2009-05-23 13:56:40 +00:00
|
|
|
|
2010-01-07 19:44:32 +00:00
|
|
|
struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr)
|
|
|
|
{
|
|
|
|
struct gsm_bts_trx *trx;
|
|
|
|
|
|
|
|
llist_for_each_entry(trx, &bts->trx_list, list) {
|
|
|
|
if (trx->nr == nr)
|
|
|
|
return trx;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-05-23 13:56:40 +00:00
|
|
|
/* Search for a BTS in the given Location Area; optionally start searching
|
|
|
|
* with start_bts (for continuing to search after the first result) */
|
|
|
|
struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
|
|
|
|
struct gsm_bts *start_bts)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct gsm_bts *bts;
|
|
|
|
int skip = 0;
|
|
|
|
|
|
|
|
if (start_bts)
|
|
|
|
skip = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < net->num_bts; i++) {
|
2009-06-21 14:17:15 +00:00
|
|
|
bts = gsm_bts_num(net, i);
|
2009-05-23 13:56:40 +00:00
|
|
|
|
|
|
|
if (skip) {
|
|
|
|
if (start_bts == bts)
|
|
|
|
skip = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-10-01 02:07:15 +00:00
|
|
|
if (lac == GSM_LAC_RESERVED_ALL_BTS || bts->location_area_code == lac)
|
2009-05-23 13:56:40 +00:00
|
|
|
return bts;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-06-20 16:15:19 +00:00
|
|
|
|
2010-03-25 03:45:30 +00:00
|
|
|
static const struct value_string auth_policy_names[] = {
|
|
|
|
{ GSM_AUTH_POLICY_CLOSED, "closed" },
|
|
|
|
{ GSM_AUTH_POLICY_ACCEPT_ALL, "accept-all" },
|
|
|
|
{ GSM_AUTH_POLICY_TOKEN, "token" },
|
2016-05-24 12:23:27 +00:00
|
|
|
{ GSM_AUTH_POLICY_REGEXP, "regexp" },
|
2010-03-25 03:45:30 +00:00
|
|
|
{ 0, NULL }
|
2009-08-12 12:42:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum gsm_auth_policy gsm_auth_policy_parse(const char *arg)
|
|
|
|
{
|
2010-03-25 03:45:30 +00:00
|
|
|
return get_string_value(auth_policy_names, arg);
|
2009-08-12 12:42:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *gsm_auth_policy_name(enum gsm_auth_policy policy)
|
|
|
|
{
|
2010-03-25 03:45:30 +00:00
|
|
|
return get_value_string(auth_policy_names, policy);
|
2009-08-12 12:42:23 +00:00
|
|
|
}
|
|
|
|
|
2010-03-25 03:45:30 +00:00
|
|
|
static const struct value_string rrlp_mode_names[] = {
|
|
|
|
{ RRLP_MODE_NONE, "none" },
|
|
|
|
{ RRLP_MODE_MS_BASED, "ms-based" },
|
|
|
|
{ RRLP_MODE_MS_PREF, "ms-preferred" },
|
|
|
|
{ RRLP_MODE_ASS_PREF, "ass-preferred" },
|
|
|
|
{ 0, NULL }
|
2009-12-13 09:53:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum rrlp_mode rrlp_mode_parse(const char *arg)
|
|
|
|
{
|
2010-03-25 03:45:30 +00:00
|
|
|
return get_string_value(rrlp_mode_names, arg);
|
2009-12-13 09:53:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *rrlp_mode_name(enum rrlp_mode mode)
|
|
|
|
{
|
2010-03-25 03:45:30 +00:00
|
|
|
return get_value_string(rrlp_mode_names, mode);
|
2009-12-13 09:53:12 +00:00
|
|
|
}
|
2009-12-15 20:36:05 +00:00
|
|
|
|
2010-04-18 13:51:20 +00:00
|
|
|
static const struct value_string bts_gprs_mode_names[] = {
|
|
|
|
{ BTS_GPRS_NONE, "none" },
|
|
|
|
{ BTS_GPRS_GPRS, "gprs" },
|
|
|
|
{ BTS_GPRS_EGPRS, "egprs" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2015-01-31 21:16:00 +00:00
|
|
|
enum bts_gprs_mode bts_gprs_mode_parse(const char *arg, int *valid)
|
2010-04-18 13:51:20 +00:00
|
|
|
{
|
2015-01-31 21:16:00 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = get_string_value(bts_gprs_mode_names, arg);
|
|
|
|
if (valid)
|
|
|
|
*valid = rc != -EINVAL;
|
|
|
|
return rc;
|
2010-04-18 13:51:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *bts_gprs_mode_name(enum bts_gprs_mode mode)
|
|
|
|
{
|
|
|
|
return get_value_string(bts_gprs_mode_names, mode);
|
|
|
|
}
|
|
|
|
|
2015-01-31 21:16:00 +00:00
|
|
|
int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode)
|
|
|
|
{
|
|
|
|
if (mode != BTS_GPRS_NONE &&
|
|
|
|
!gsm_bts_has_feature(bts, BTS_FEAT_GPRS)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (mode == BTS_GPRS_EGPRS &&
|
|
|
|
!gsm_bts_has_feature(bts, BTS_FEAT_EGPRS)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-12-15 20:36:05 +00:00
|
|
|
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
|
|
|
|
{
|
|
|
|
struct gsm_meas_rep *meas_rep;
|
|
|
|
|
|
|
|
meas_rep = &lchan->meas_rep[lchan->meas_rep_idx];
|
|
|
|
memset(meas_rep, 0, sizeof(*meas_rep));
|
|
|
|
meas_rep->lchan = lchan;
|
|
|
|
lchan->meas_rep_idx = (lchan->meas_rep_idx + 1)
|
|
|
|
% ARRAY_SIZE(lchan->meas_rep);
|
|
|
|
|
|
|
|
return meas_rep;
|
|
|
|
}
|
2009-12-27 19:56:38 +00:00
|
|
|
|
2010-06-14 20:44:42 +00:00
|
|
|
int gsm_btsmodel_set_feature(struct gsm_bts_model *bts, enum gsm_bts_features feat)
|
|
|
|
{
|
|
|
|
return bitvec_set_bit_pos(&bts->features, feat, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat)
|
|
|
|
{
|
|
|
|
return bitvec_get_bit_pos(&bts->model->features, feat);
|
|
|
|
}
|
|
|
|
|
2010-01-10 17:01:52 +00:00
|
|
|
int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type)
|
2009-12-27 19:56:38 +00:00
|
|
|
{
|
2010-01-10 17:01:52 +00:00
|
|
|
struct gsm_bts_model *model;
|
|
|
|
|
|
|
|
model = bts_model_find(type);
|
|
|
|
if (!model)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2009-12-27 19:56:38 +00:00
|
|
|
bts->type = type;
|
2010-01-10 17:01:52 +00:00
|
|
|
bts->model = model;
|
2009-12-27 19:56:38 +00:00
|
|
|
|
bsc: on-demand setup of nanoBTS and HSL femto sockets
The daemons set up nanoBTS and HSL femto sockets by default, ie. the
three sockets to support these two drivers are open even if we have
no BTS of that kind.
This patch enables on-demand socket creation, ie. we only enable them
if we have one BTS at least that requires it.
I added two new attributes to the gsm_bts object, they are:
* the start() function includes the code that we need to run to start
the BTS. This new function contains the socket creation in the
particular case of nanoBTS and HSL femto.
* the started boolean, which is used to know if we have already
started the BTS, ie. we have already invoked start().
Note that, I have splitted the bts_model_*_init() function into two
functions, the _init() functions that register the BTS driver
and the _start() functions that start BTS driver on-demand.
While I was at it, I added several changes/cleanups to this patch:
* Group all bts_model_*_init() calls into one function bts_init(),
which is called in the initialization path of osmo-nitb and
osmo-bsc.
* Add openbsc/bss.h that contains the declaration of
bsc_bootstrap_network, bsc_shutdown_net and bts_init.
* Add missing e1inp_init() in osmo-bsc.
* Fix missing declaration of hsl_setup in openbsc/e1_input.h
2011-05-14 09:32:48 +00:00
|
|
|
if (model->start && !model->started) {
|
|
|
|
int ret = model->start(bts->network);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
model->started = true;
|
|
|
|
}
|
|
|
|
|
2009-12-27 19:56:38 +00:00
|
|
|
switch (bts->type) {
|
|
|
|
case GSM_BTS_TYPE_NANOBTS:
|
2012-07-02 17:51:55 +00:00
|
|
|
case GSM_BTS_TYPE_OSMO_SYSMO:
|
2009-12-27 19:56:38 +00:00
|
|
|
/* Set the default OML Stream ID to 0xff */
|
|
|
|
bts->oml_tei = 0xff;
|
|
|
|
bts->c0->nominal_power = 23;
|
|
|
|
break;
|
2011-02-13 21:13:28 +00:00
|
|
|
case GSM_BTS_TYPE_RBS2000:
|
|
|
|
INIT_LLIST_HEAD(&bts->rbs2000.is.conn_groups);
|
2011-02-13 21:45:02 +00:00
|
|
|
INIT_LLIST_HEAD(&bts->rbs2000.con.conn_groups);
|
2011-02-13 21:13:28 +00:00
|
|
|
break;
|
2012-02-03 18:44:37 +00:00
|
|
|
case GSM_BTS_TYPE_BS11:
|
|
|
|
case GSM_BTS_TYPE_UNKNOWN:
|
|
|
|
case GSM_BTS_TYPE_NOKIA_SITE:
|
2015-02-07 12:27:36 +00:00
|
|
|
/* Set default BTS reset timer */
|
|
|
|
bts->nokia.bts_reset_timer_cnf = 15;
|
2012-09-11 09:53:08 +00:00
|
|
|
case _NUM_GSM_BTS_TYPE:
|
2012-02-03 18:44:37 +00:00
|
|
|
break;
|
2009-12-27 19:56:38 +00:00
|
|
|
}
|
2010-01-10 17:01:52 +00:00
|
|
|
|
|
|
|
return 0;
|
2009-12-27 19:56:38 +00:00
|
|
|
}
|
2011-06-05 11:31:33 +00:00
|
|
|
|
|
|
|
struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_type type,
|
2015-11-20 09:43:31 +00:00
|
|
|
uint8_t bsic)
|
2011-06-05 11:31:33 +00:00
|
|
|
{
|
|
|
|
struct gsm_bts_model *model = bts_model_find(type);
|
|
|
|
struct gsm_bts *bts;
|
|
|
|
|
2011-06-06 15:52:56 +00:00
|
|
|
if (!model && type != GSM_BTS_TYPE_UNKNOWN)
|
2011-06-05 11:31:33 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
bts = gsm_bts_alloc(net);
|
|
|
|
if (!bts)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
bts->network = net;
|
|
|
|
bts->nr = net->num_bts++;
|
|
|
|
bts->type = type;
|
|
|
|
bts->model = model;
|
|
|
|
bts->bsic = bsic;
|
2016-05-11 10:45:13 +00:00
|
|
|
bts->dtxu = GSM48_DTX_SHALL_NOT_BE_USED;
|
|
|
|
bts->dtxd = false;
|
2011-06-05 11:31:33 +00:00
|
|
|
bts->neigh_list_manual_mode = 0;
|
|
|
|
bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */
|
|
|
|
bts->si_common.cell_sel_par.rxlev_acc_min = 0;
|
2016-04-15 14:04:46 +00:00
|
|
|
bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list;
|
|
|
|
bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list;
|
|
|
|
bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST;
|
|
|
|
bts->si_common.si2quater_neigh_list.thresh_hi = 0;
|
|
|
|
osmo_earfcn_init(&bts->si_common.si2quater_neigh_list);
|
2011-06-05 11:31:33 +00:00
|
|
|
bts->si_common.neigh_list.data = bts->si_common.data.neigh_list;
|
|
|
|
bts->si_common.neigh_list.data_len =
|
|
|
|
sizeof(bts->si_common.data.neigh_list);
|
|
|
|
bts->si_common.si5_neigh_list.data = bts->si_common.data.si5_neigh_list;
|
|
|
|
bts->si_common.si5_neigh_list.data_len =
|
|
|
|
sizeof(bts->si_common.data.si5_neigh_list);
|
|
|
|
bts->si_common.cell_alloc.data = bts->si_common.data.cell_alloc;
|
|
|
|
bts->si_common.cell_alloc.data_len =
|
|
|
|
sizeof(bts->si_common.data.cell_alloc);
|
|
|
|
bts->si_common.rach_control.re = 1; /* no re-establishment */
|
|
|
|
bts->si_common.rach_control.tx_integer = 9; /* 12 slots spread - 217/115 slots delay */
|
|
|
|
bts->si_common.rach_control.max_trans = 3; /* 7 retransmissions */
|
|
|
|
bts->si_common.rach_control.t2 = 4; /* no emergency calls */
|
2012-10-13 05:27:47 +00:00
|
|
|
bts->si_common.chan_desc.att = 1; /* attachment required */
|
|
|
|
bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; /* paging frames */
|
|
|
|
bts->si_common.chan_desc.bs_ag_blks_res = 1; /* reserved AGCH blocks */
|
2012-12-26 23:02:01 +00:00
|
|
|
bts->si_common.chan_desc.t3212 = 5; /* Use 30 min periodic update interval as sane default */
|
2013-03-10 10:49:35 +00:00
|
|
|
set_radio_link_timeout(&bts->si_common.cell_options, 32);
|
|
|
|
/* Use RADIO LINK TIMEOUT of 32 seconds */
|
2011-06-05 11:31:33 +00:00
|
|
|
|
|
|
|
llist_add_tail(&bts->list, &net->bts_list);
|
|
|
|
|
|
|
|
INIT_LLIST_HEAD(&bts->abis_queue);
|
|
|
|
|
2011-08-05 11:51:27 +00:00
|
|
|
INIT_LLIST_HEAD(&bts->loc_list);
|
|
|
|
|
2011-06-05 11:31:33 +00:00
|
|
|
return bts;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts)
|
|
|
|
{
|
|
|
|
raid->mcc = bts->network->country_code;
|
|
|
|
raid->mnc = bts->network->network_code;
|
|
|
|
raid->lac = bts->location_area_code;
|
|
|
|
raid->rac = bts->gprs.rac;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gsm48_ra_id_by_bts(uint8_t *buf, struct gsm_bts *bts)
|
|
|
|
{
|
|
|
|
struct gprs_ra_id raid;
|
|
|
|
|
|
|
|
gprs_ra_id_by_bts(&raid, bts);
|
|
|
|
|
|
|
|
return gsm48_construct_ra(buf, &raid);
|
|
|
|
}
|
2011-06-09 19:48:49 +00:00
|
|
|
|
|
|
|
int gsm_parse_reg(void *ctx, regex_t *reg, char **str, int argc, const char **argv)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
if (*str) {
|
|
|
|
talloc_free(*str);
|
|
|
|
*str = NULL;
|
|
|
|
}
|
|
|
|
regfree(reg);
|
|
|
|
|
|
|
|
if (argc > 0) {
|
|
|
|
*str = talloc_strdup(ctx, argv[0]);
|
|
|
|
ret = regcomp(reg, argv[0], 0);
|
|
|
|
|
|
|
|
/* handle compilation failures */
|
|
|
|
if (ret != 0) {
|
|
|
|
talloc_free(*str);
|
|
|
|
*str = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-17 13:46:17 +00:00
|
|
|
/* Assume there are only 256 possible bts */
|
|
|
|
osmo_static_assert(sizeof(((struct gsm_bts *) 0)->nr) == 1, _bts_nr_is_256);
|
|
|
|
static void depends_calc_index_bit(int bts_nr, int *idx, int *bit)
|
|
|
|
{
|
|
|
|
*idx = bts_nr / (8 * 4);
|
|
|
|
*bit = bts_nr % (8 * 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bts_depend_mark(struct gsm_bts *bts, int dep)
|
|
|
|
{
|
|
|
|
int idx, bit;
|
|
|
|
depends_calc_index_bit(dep, &idx, &bit);
|
|
|
|
|
|
|
|
bts->depends_on[idx] |= 1 << bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bts_depend_clear(struct gsm_bts *bts, int dep)
|
|
|
|
{
|
|
|
|
int idx, bit;
|
|
|
|
depends_calc_index_bit(dep, &idx, &bit);
|
|
|
|
|
|
|
|
bts->depends_on[idx] &= ~(1 << bit);
|
|
|
|
}
|
|
|
|
|
2014-12-17 14:44:32 +00:00
|
|
|
int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other)
|
2014-12-17 13:46:17 +00:00
|
|
|
{
|
|
|
|
int idx, bit;
|
|
|
|
depends_calc_index_bit(other->nr, &idx, &bit);
|
|
|
|
|
|
|
|
/* Check if there is a depends bit */
|
|
|
|
return (base->depends_on[idx] & (1 << bit)) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bts_is_online(struct gsm_bts *bts)
|
|
|
|
{
|
|
|
|
/* TODO: support E1 BTS too */
|
|
|
|
if (!is_ipaccess_bts(bts))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!bts->oml_link)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return bts->mo.nm_state.operational == NM_OPSTATE_ENABLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bts_depend_check(struct gsm_bts *bts)
|
|
|
|
{
|
|
|
|
struct gsm_bts *other_bts;
|
|
|
|
|
|
|
|
llist_for_each_entry(other_bts, &bts->network->bts_list, list) {
|
|
|
|
if (!bts_depend_is_depedency(bts, other_bts))
|
|
|
|
continue;
|
|
|
|
if (bts_is_online(other_bts))
|
|
|
|
continue;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|