Allow configuration of SI5 neighbor list != SI2 neighbor list

This introducecs the new VTY command "neighbor-list mode manual-si5"
in combination with "si5 neighbor-list (add|del) arfcn <0-1024>",
which allows you to (optionally) have neighbor channel lists that
differ in SI5 and in SI2.
This commit is contained in:
Harald Welte
2011-02-15 11:43:27 +01:00
parent b01bf33ad4
commit 64c07d213c
4 changed files with 76 additions and 14 deletions

View File

@@ -491,6 +491,12 @@ struct gsm_bts_gprs_nsvc {
struct gsm_nm_state nm_state;
};
enum neigh_list_manual_mode {
NL_MODE_AUTOMATIC = 0,
NL_MODE_MANUAL = 1,
NL_MODE_MANUAL_SI5SEP = 2, /* SI2 and SI5 have separate neighbor lists */
};
/* One BTS */
struct gsm_bts {
/* list header in net->bts_list */
@@ -542,7 +548,7 @@ struct gsm_bts {
struct gsm_nm_state nm_state;
} site_mgr;
int neigh_list_manual_mode;
enum neigh_list_manual_mode neigh_list_manual_mode;
/* parameters from which we build SYSTEM INFORMATION */
struct {
struct gsm48_rach_control rach_control;
@@ -553,10 +559,13 @@ struct gsm_bts {
struct gsm48_control_channel_descr chan_desc;
struct bitvec neigh_list;
struct bitvec cell_alloc;
struct bitvec si5_neigh_list;
struct {
/* bitmask large enough for all possible ARFCN's */
u_int8_t neigh_list[1024/8];
u_int8_t cell_alloc[1024/8];
/* If the user wants a different neighbor list in SI5 than in SI2 */
u_int8_t si5_neigh_list[1024/8];
} data;
} si_common;

View File

@@ -76,6 +76,13 @@ static const struct value_string gprs_bssgp_cfg_strs[] = {
{ 0, NULL }
};
static const struct value_string bts_neigh_mode_strs[] = {
{ NL_MODE_AUTOMATIC, "automatic" },
{ NL_MODE_MANUAL, "manual" },
{ NL_MODE_MANUAL_SI5SEP, "manual-si5" },
{ 0, NULL }
};
struct cmd_node net_node = {
GSMNET_NODE,
"%s(network)#",
@@ -495,14 +502,21 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " paging free %d%s", bts->paging.free_chans_need, VTY_NEWLINE);
vty_out(vty, " neighbor-list mode %s%s",
bts->neigh_list_manual_mode ? "manual" : "automatic", VTY_NEWLINE);
if (bts->neigh_list_manual_mode) {
get_value_string(bts_neigh_mode_strs, bts->neigh_list_manual_mode), VTY_NEWLINE);
if (bts->neigh_list_manual_mode != NL_MODE_AUTOMATIC) {
for (i = 0; i < 1024; i++) {
if (bitvec_get_bit_pos(&bts->si_common.neigh_list, i))
vty_out(vty, " neighbor-list add arfcn %u%s",
i, VTY_NEWLINE);
}
}
if (bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP) {
for (i = 0; i < 1024; i++) {
if (bitvec_get_bit_pos(&bts->si_common.si5_neigh_list, i))
vty_out(vty, " si5 neighbor-list add arfcn %u%s",
i, VTY_NEWLINE);
}
}
config_write_bts_gprs(vty, bts);
@@ -2136,21 +2150,28 @@ DEFUN(cfg_bts_si_static, cfg_bts_si_static_cmd,
}
DEFUN(cfg_bts_neigh_mode, cfg_bts_neigh_mode_cmd,
"neighbor-list mode (automatic|manual)",
"neighbor-list mode (automatic|manual|manual-si5)",
"Neighbor List\n" "Mode of Neighbor List generation\n"
"Automatically from all BTS in this OpenBSC\n" "Manual\n")
"Automatically from all BTS in this OpenBSC\n" "Manual\n"
"Manual with different lists for SI2 and SI5\n")
{
struct gsm_bts *bts = vty->index;
int mode = get_string_value(bts_neigh_mode_strs, argv[0]);
if (!strcmp(argv[0], "manual")) {
switch (mode) {
case NL_MODE_MANUAL_SI5SEP:
case NL_MODE_MANUAL:
/* make sure we clear the current list when switching to
* manual mode */
if (bts->neigh_list_manual_mode == 0)
memset(&bts->si_common.data.neigh_list, 0,
sizeof(bts->si_common.data.neigh_list));
bts->neigh_list_manual_mode = 1;
} else
bts->neigh_list_manual_mode = 0;
break;
default:
break;
}
bts->neigh_list_manual_mode = mode;
return CMD_SUCCESS;
}
@@ -2179,6 +2200,29 @@ DEFUN(cfg_bts_neigh, cfg_bts_neigh_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_si5_neigh, cfg_bts_si5_neigh_cmd,
"si5 neighbor-list (add|del) arfcn <0-1024>",
"SI5 Neighbor List\n" "Add to manual SI5 neighbor list\n"
"Delete from SI5 manual neighbor list\n" "ARFCN of neighbor\n"
"ARFCN of neighbor\n")
{
struct gsm_bts *bts = vty->index;
struct bitvec *bv = &bts->si_common.si5_neigh_list;
uint16_t arfcn = atoi(argv[1]);
if (!bts->neigh_list_manual_mode) {
vty_out(vty, "%% Cannot configure neighbor list in "
"automatic mode%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (!strcmp(argv[0], "add"))
bitvec_set_bit_pos(bv, arfcn, 1);
else
bitvec_set_bit_pos(bv, arfcn, 0);
return CMD_SUCCESS;
}
#define TRX_TEXT "Radio Transceiver\n"
@@ -2679,6 +2723,7 @@ int bsc_vty_init(void)
install_element(BTS_NODE, &cfg_bts_si_static_cmd);
install_element(BTS_NODE, &cfg_bts_neigh_mode_cmd);
install_element(BTS_NODE, &cfg_bts_neigh_cmd);
install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd);
install_element(BTS_NODE, &cfg_trx_cmd);
install_node(&trx_node, dummy_config_write);

View File

@@ -214,6 +214,9 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
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);

View File

@@ -199,16 +199,21 @@ static int generate_cell_chan_list(u_int8_t *chan_list, struct gsm_bts *bts)
}
/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
static int generate_bcch_chan_list(u_int8_t *chan_list, struct gsm_bts *bts)
static int generate_bcch_chan_list(u_int8_t *chan_list, struct gsm_bts *bts, int si5)
{
struct gsm_bts *cur_bts;
struct bitvec *bv = &bts->si_common.neigh_list;
struct bitvec *bv;
if (si5 && bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP)
bv = &bts->si_common.si5_neigh_list;
else
bv = &bts->si_common.neigh_list;
/* Zero-initialize the bit-vector */
memset(bv->data, 0, bv->data_len);
/* Generate list of neighbor cells if we are in automatic mode */
if (bts->neigh_list_manual_mode == 0) {
if (bts->neigh_list_manual_mode == NL_MODE_AUTOMATIC) {
/* first we generate a bitvec of the BCCH ARFCN's in our BSC */
llist_for_each_entry(cur_bts, &bts->network->bts_list, list) {
if (cur_bts == bts)
@@ -259,7 +264,7 @@ static int generate_si2(u_int8_t *output, struct gsm_bts *bts)
si2->header.skip_indicator = 0;
si2->header.system_information = GSM48_MT_RR_SYSINFO_2;
rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts);
rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts, 0);
if (rc < 0)
return rc;
@@ -376,7 +381,7 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
si5->rr_protocol_discriminator = GSM48_PDISC_RR;
si5->skip_indicator = 0;
si5->system_information = GSM48_MT_RR_SYSINFO_5;
rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts);
rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts, 1);
if (rc < 0)
return rc;