summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/src/libbsc/bsc_init.c63
-rw-r--r--openbsc/src/libbsc/system_information.c243
2 files changed, 265 insertions, 41 deletions
diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c
index 441c0a9f0..6d00374e0 100644
--- a/openbsc/src/libbsc/bsc_init.c
+++ b/openbsc/src/libbsc/bsc_init.c
@@ -95,18 +95,10 @@ int bsc_shutdown_net(struct gsm_network *net)
return 0;
}
-static int generate_and_rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i)
+static int rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i, int si_len)
{
struct gsm_bts *bts = trx->bts;
- int si_len, rc, j;
-
- /* Only generate SI if this SI is not in "static" (user-defined) mode */
- if (!(bts->si_mode_static & (1 << i))) {
- rc = gsm_generate_si(bts, i);
- if (rc < 0)
- return rc;
- si_len = rc;
- }
+ int rc, j;
DEBUGP(DRR, "SI%s: %s\n", get_value_string(osmo_sitype_strs, i),
osmo_hexdump(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN));
@@ -134,11 +126,11 @@ static int generate_and_rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i
}
} else
rc = rsl_sacch_filling(trx, osmo_sitype2rsl(i),
- GSM_BTS_SI(bts, i), rc);
+ GSM_BTS_SI(bts, i), si_len);
break;
default:
rc = rsl_bcch_info(trx, osmo_sitype2rsl(i),
- GSM_BTS_SI(bts, i), rc);
+ GSM_BTS_SI(bts, i), si_len);
break;
}
@@ -150,6 +142,8 @@ static int set_system_infos(struct gsm_bts_trx *trx)
{
int i, rc;
struct gsm_bts *bts = trx->bts;
+ uint8_t gen_si[_MAX_SYSINFO_TYPE], n_si = 0, n;
+ int si_len[_MAX_SYSINFO_TYPE];
bts->si_common.cell_sel_par.ms_txpwr_max_ccch =
ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
@@ -159,26 +153,55 @@ static int set_system_infos(struct gsm_bts_trx *trx)
if (trx == bts->c0) {
/* 1...4 are always present on a C0 TRX */
- for (i = SYSINFO_TYPE_1; i <= SYSINFO_TYPE_4; i++)
- bts->si_valid |= (1 << i);
+ gen_si[n_si++] = SYSINFO_TYPE_1;
+ gen_si[n_si++] = SYSINFO_TYPE_2;
+ gen_si[n_si++] = SYSINFO_TYPE_2bis;
+ gen_si[n_si++] = SYSINFO_TYPE_2ter;
+ gen_si[n_si++] = SYSINFO_TYPE_3;
+ gen_si[n_si++] = SYSINFO_TYPE_4;
/* 13 is always present on a C0 TRX of a GPRS BTS */
if (bts->gprs.mode != BTS_GPRS_NONE)
- bts->si_valid |= (1 << SYSINFO_TYPE_13);
+ gen_si[n_si++] = SYSINFO_TYPE_13;
}
/* 5 and 6 are always present on every TRX */
- bts->si_valid |= (1 << SYSINFO_TYPE_5);
- bts->si_valid |= (1 << SYSINFO_TYPE_6);
+ gen_si[n_si++] = SYSINFO_TYPE_5;
+ gen_si[n_si++] = SYSINFO_TYPE_5bis;
+ gen_si[n_si++] = SYSINFO_TYPE_5ter;
+ gen_si[n_si++] = SYSINFO_TYPE_6;
+
+ /* Second, we generate the selected SI via RSL */
+
+ for (n = 0; n < n_si; n++) {
+ i = gen_si[n];
+ bts->si_valid |= (1 << i);
+ /* Only generate SI if this SI is not in "static" (user-defined) mode */
+ if (!(bts->si_mode_static & (1 << i))) {
+ rc = gsm_generate_si(bts, i);
+ if (rc < 0)
+ goto err_out;
+ si_len[i] = rc;
+ } else {
+ if (i == SYSINFO_TYPE_5 || i == SYSINFO_TYPE_5bis
+ || i == SYSINFO_TYPE_5ter)
+ si_len[i] = 18;
+ else if (i == SYSINFO_TYPE_6)
+ si_len[i] = 11;
+ else
+ si_len[i] = 23;
+ }
+ }
+
+ /* Third, we send the selected SI via RSL */
- /* Second, we generate and send the selected SI via RSL */
for (i = SYSINFO_TYPE_1; i < _MAX_SYSINFO_TYPE; i++) {
if (!(bts->si_valid & (1 << i)))
continue;
- rc = generate_and_rsl_si(trx, i);
+ rc = rsl_si(trx, i, si_len[i]);
if (rc < 0)
- goto err_out;
+ return rc;
}
return 0;
diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c
index 9842a9dfd..360d229ad 100644
--- a/openbsc/src/libbsc/system_information.c
+++ b/openbsc/src/libbsc/system_information.c
@@ -74,16 +74,12 @@ static int freq_list_bmrel_set_arfcn(uint8_t *chan_list, unsigned int arfcn)
if (arfcn == min_arfcn)
return 0;
- if (arfcn < min_arfcn) {
- LOGP(DRR, LOGL_ERROR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn);
- return -EINVAL;
- }
- if (arfcn > min_arfcn + 111) {
+ if (((arfcn - min_arfcn) & 1023) > 111) {
LOGP(DRR, LOGL_ERROR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn);
return -EINVAL;
}
- bitno = (arfcn - min_arfcn);
+ bitno = (arfcn - min_arfcn) & 1023;
byte = bitno / 8;
bit = bitno % 8;
@@ -94,19 +90,22 @@ static int freq_list_bmrel_set_arfcn(uint8_t *chan_list, unsigned int arfcn)
/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
- const struct gsm_bts *bts)
+ const struct gsm_bts *bts, int bis, int ter)
{
- int i, rc, min = 1024, max = -1;
+ int i, rc, min = -1, max = -1, pgsm = 0;
memset(chan_list, 0, 16);
- /* P-GSM-only handsets only support 'bit map 0 format' */
if (bts->band == GSM_BAND_900
- && bts->c0->arfcn >= 1 && bts->c0->arfcn <= 124) {
+ && bts->c0->arfcn >= 1 && bts->c0->arfcn <= 124)
+ pgsm = 1;
+ /* P-GSM-only handsets only support 'bit map 0 format' */
+ if (!bis && !ter && pgsm) {
chan_list[0] = 0;
for (i = 0; i < bv->data_len*8; i++) {
- if (bitvec_get_bit_pos(bv, i)) {
+ if (i >= 1 && i <= 124
+ && bitvec_get_bit_pos(bv, i)) {
rc = freq_list_bm0_set_arfcn(chan_list, i);
if (rc < 0)
return rc;
@@ -119,10 +118,30 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
chan_list[0] = 0x8e;
for (i = 0; i < bv->data_len*8; i++) {
- if (bitvec_get_bit_pos(bv, i)) {
- if (i < min)
+ /* in case of SI2 or SI5 allow all neighbours in same band
+ * in case of SI*bis, allow neighbours in same band ouside pgsm
+ * in case of SI*ter, allow neighbours in different bands
+ */
+ if (bitvec_get_bit_pos(bv, i)
+ && ((!bis && !ter && gsm_arfcn2band(i) == bts->band)
+ || (bis && pgsm && gsm_arfcn2band(i) == bts->band && (i < 1 || i > 124))
+ || (ter && gsm_arfcn2band(i) != bts->band))) {
+ /* 955..1023 < 0..885 */
+ if (min < 0)
+ min = i;
+ if (i >= 955 && min < 955)
+ min = i;
+ if (i >= 955 && min >= 955 && i < min)
min = i;
- if (i > max)
+ if (i < 955 && min < 955 && i < min)
+ min = i;
+ if (max < 0)
+ max = i;
+ if (i < 955 && max >= 955)
+ max = i;
+ if (i >= 955 && max >= 955 && i > max)
+ max = i;
+ if (i < 955 && max < 955 && i > max)
max = i;
}
}
@@ -133,7 +152,7 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
return 0;
}
- if ((max - min) > 111) {
+ if (((max - min) & 1023) > 111) {
LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, "
"distance > 111\n", min, max);
return -EINVAL;
@@ -144,7 +163,11 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
chan_list[2] = (min & 1) << 7;
for (i = 0; i < bv->data_len*8; i++) {
- if (bitvec_get_bit_pos(bv, i)) {
+ /* see notes above */
+ if (bitvec_get_bit_pos(bv, i)
+ && ((!bis && !ter && gsm_arfcn2band(i) == bts->band)
+ || (bis && pgsm && gsm_arfcn2band(i) == bts->band && (i < 1 || i > 124))
+ || (ter && gsm_arfcn2band(i) != bts->band))) {
rc = freq_list_bmrel_set_arfcn(chan_list, i);
if (rc < 0)
return rc;
@@ -179,11 +202,12 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
}
/* then we generate a GSM 04.08 frequency list from the bitvec */
- return bitvec2freq_list(chan_list, bv, bts);
+ return bitvec2freq_list(chan_list, bv, bts, 0, 0);
}
/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
-static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts, int si5)
+static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts,
+ int si5, int bis, int ter)
{
struct gsm_bts *cur_bts;
struct bitvec *bv;
@@ -207,7 +231,28 @@ static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts, int
}
/* then we generate a GSM 04.08 frequency list from the bitvec */
- return bitvec2freq_list(chan_list, bv, bts);
+ return bitvec2freq_list(chan_list, bv, bts, bis, ter);
+}
+
+static int list_arfcn(uint8_t *chan_list, uint8_t mask, char *text)
+{
+ int n = 0, i;
+ struct gsm_sysinfo_freq freq[1024];
+
+ memset(freq, 0, sizeof(freq));
+ gsm48_decode_freq_list(freq, chan_list, 16, 0xce, 1);
+ for (i = 0; i < 1024; i++) {
+ if (freq[i].mask) {
+ if (!n)
+ LOGP(DRR, LOGL_INFO, "%s", text);
+ LOGPC(DRR, LOGL_INFO, " %d", i);
+ n++;
+ }
+ }
+ if (n)
+ LOGPC(DRR, LOGL_INFO, "\n");
+
+ return n;
}
static int generate_si1(uint8_t *output, struct gsm_bts *bts)
@@ -226,6 +271,7 @@ static int generate_si1(uint8_t *output, struct gsm_bts *bts)
rc = generate_cell_chan_list(si1->cell_channel_description, bts);
if (rc < 0)
return rc;
+ list_arfcn(si1->cell_channel_description, 0xce, "Serving cell:");
si1->rach_control = bts->si_common.rach_control;
@@ -248,9 +294,11 @@ static int generate_si2(uint8_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, 0);
+ rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts, 0, 0, 0);
if (rc < 0)
return rc;
+ list_arfcn(si2->bcch_frequency_list, 0xce,
+ "Neighbour cells in same band:");
si2->ncc_permitted = bts->si_common.ncc_permitted;
si2->rach_control = bts->si_common.rach_control;
@@ -258,6 +306,65 @@ static int generate_si2(uint8_t *output, struct gsm_bts *bts)
return sizeof(*si2);
}
+static int generate_si2bis(uint8_t *output, struct gsm_bts *bts)
+{
+ int rc;
+ struct gsm48_system_information_type_2bis *si2b =
+ (struct gsm48_system_information_type_2bis *) output;
+ int n;
+
+ memset(si2b, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ si2b->header.l2_plen = (22 << 2) | 1;
+ si2b->header.rr_protocol_discriminator = GSM48_PDISC_RR;
+ si2b->header.skip_indicator = 0;
+ si2b->header.system_information = GSM48_MT_RR_SYSINFO_2bis;
+
+ rc = generate_bcch_chan_list(si2b->bcch_frequency_list, bts, 0, 1, 0);
+ if (rc < 0)
+ return rc;
+ n = list_arfcn(si2b->bcch_frequency_list, 0xce,
+ "Neighbour cells in same band, but outside P-GSM:");
+ if (n) {
+ /* indicate in SI2 and SI2bis: there is an extension */
+ struct gsm48_system_information_type_2 *si2 =
+ (struct gsm48_system_information_type_2 *)
+ bts->si_buf[SYSINFO_TYPE_2];
+ si2->bcch_frequency_list[0] |= 0x20;
+ si2b->bcch_frequency_list[0] |= 0x20;
+ } else
+ bts->si_valid &= ~(1 << SYSINFO_TYPE_2bis);
+
+ si2b->rach_control = bts->si_common.rach_control;
+
+ return sizeof(*si2b);
+}
+
+static int generate_si2ter(uint8_t *output, struct gsm_bts *bts)
+{
+ int rc;
+ struct gsm48_system_information_type_2ter *si2t =
+ (struct gsm48_system_information_type_2ter *) output;
+ int n;
+
+ memset(si2t, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ si2t->header.l2_plen = (22 << 2) | 1;
+ si2t->header.rr_protocol_discriminator = GSM48_PDISC_RR;
+ si2t->header.skip_indicator = 0;
+ si2t->header.system_information = GSM48_MT_RR_SYSINFO_2ter;
+
+ rc = generate_bcch_chan_list(si2t->ext_bcch_frequency_list, bts, 0, 0, 1);
+ if (rc < 0)
+ return rc;
+ n = list_arfcn(si2t->ext_bcch_frequency_list, 0x8e,
+ "Neighbour cells in different band:");
+ if (!n)
+ bts->si_valid &= ~(1 << SYSINFO_TYPE_2ter);
+
+ return sizeof(*si2t);
+}
+
static struct gsm48_si_ro_info si_info = {
.selection_params = {
.present = 0,
@@ -304,6 +411,13 @@ static int generate_si3(uint8_t *output, struct gsm_bts *bts)
si3->cell_sel_par = bts->si_common.cell_sel_par;
si3->rach_control = bts->si_common.rach_control;
+ if ((bts->si_valid & (1 << SYSINFO_TYPE_2ter))) {
+ LOGP(DRR, LOGL_INFO, "SI 2ter is included.\n");
+ si_info.si2ter_indicator = 1;
+ } else {
+ si_info.si2ter_indicator = 0;
+ }
+
/* SI3 Rest Octets (10.5.2.34), containing
CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME
Power Offset, 2ter Indicator, Early Classmark Sending,
@@ -370,9 +484,92 @@ static int generate_si5(uint8_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, 1);
+ rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts, 1, 0, 0);
+ if (rc < 0)
+ return rc;
+ list_arfcn(si5->bcch_frequency_list, 0xce,
+ "Neighbour cells in same band:");
+
+ /* 04.08 9.1.37: L2 Pseudo Length of 18 */
+ return l2_plen;
+}
+
+static int generate_si5bis(uint8_t *output, struct gsm_bts *bts)
+{
+ struct gsm48_system_information_type_5bis *si5b;
+ int rc, l2_plen = 18;
+ int n;
+
+ memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ /* ip.access nanoBTS needs l2_plen!! */
+ switch (bts->type) {
+ case GSM_BTS_TYPE_NANOBTS:
+ case GSM_BTS_TYPE_HSL_FEMTO:
+ *output++ = (l2_plen << 2) | 1;
+ l2_plen++;
+ break;
+ default:
+ break;
+ }
+
+ si5b = (struct gsm48_system_information_type_5bis *) output;
+
+ /* l2 pseudo length, not part of msg: 18 */
+ si5b->rr_protocol_discriminator = GSM48_PDISC_RR;
+ si5b->skip_indicator = 0;
+ si5b->system_information = GSM48_MT_RR_SYSINFO_5bis;
+ rc = generate_bcch_chan_list(si5b->bcch_frequency_list, bts, 1, 1, 0);
+ if (rc < 0)
+ return rc;
+ n = list_arfcn(si5b->bcch_frequency_list, 0xce,
+ "Neighbour cells in same band, but outside P-GSM:");
+ if (n) {
+ /* indicate in SI5 and SI5bis: there is an extension */
+ struct gsm48_system_information_type_5 *si5 =
+ (struct gsm48_system_information_type_5 *)
+ bts->si_buf[SYSINFO_TYPE_5];
+ si5->bcch_frequency_list[0] |= 0x20;
+ si5b->bcch_frequency_list[0] |= 0x20;
+ } else
+ bts->si_valid &= ~(1 << SYSINFO_TYPE_5bis);
+
+ /* 04.08 9.1.37: L2 Pseudo Length of 18 */
+ return l2_plen;
+}
+
+static int generate_si5ter(uint8_t *output, struct gsm_bts *bts)
+{
+ struct gsm48_system_information_type_5ter *si5t;
+ int rc, l2_plen = 18;
+ int n;
+
+ memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ /* ip.access nanoBTS needs l2_plen!! */
+ switch (bts->type) {
+ case GSM_BTS_TYPE_NANOBTS:
+ case GSM_BTS_TYPE_HSL_FEMTO:
+ *output++ = (l2_plen << 2) | 1;
+ l2_plen++;
+ break;
+ default:
+ break;
+ }
+
+ si5t = (struct gsm48_system_information_type_5ter *) output;
+
+ /* l2 pseudo length, not part of msg: 18 */
+ si5t->rr_protocol_discriminator = GSM48_PDISC_RR;
+ si5t->skip_indicator = 0;
+ si5t->system_information = GSM48_MT_RR_SYSINFO_5ter;
+ rc = generate_bcch_chan_list(si5t->bcch_frequency_list, bts, 1, 0, 1);
if (rc < 0)
return rc;
+ n = list_arfcn(si5t->bcch_frequency_list, 0x8e,
+ "Neighbour cells in different band:");
+ if (!n)
+ bts->si_valid &= ~(1 << SYSINFO_TYPE_5ter);
/* 04.08 9.1.37: L2 Pseudo Length of 18 */
return l2_plen;
@@ -481,9 +678,13 @@ typedef int (*gen_si_fn_t)(uint8_t *output, struct gsm_bts *bts);
static const gen_si_fn_t gen_si_fn[_MAX_SYSINFO_TYPE] = {
[SYSINFO_TYPE_1] = &generate_si1,
[SYSINFO_TYPE_2] = &generate_si2,
+ [SYSINFO_TYPE_2bis] = &generate_si2bis,
+ [SYSINFO_TYPE_2ter] = &generate_si2ter,
[SYSINFO_TYPE_3] = &generate_si3,
[SYSINFO_TYPE_4] = &generate_si4,
[SYSINFO_TYPE_5] = &generate_si5,
+ [SYSINFO_TYPE_5bis] = &generate_si5bis,
+ [SYSINFO_TYPE_5ter] = &generate_si5ter,
[SYSINFO_TYPE_6] = &generate_si6,
[SYSINFO_TYPE_13] = &generate_si13,
};