aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2009-12-01 18:04:30 +0530
committerHarald Welte <laforge@gnumonks.org>2009-12-01 18:04:30 +0530
commita43f789a0a124c322146280ab00935b75f505617 (patch)
tree48f452451dd4e67294231e34214ef7d6ca25afbe /openbsc/src
parent29b9cf844686b84c5f19ee9b6d62fe921d68f3fc (diff)
Replace template-based SYSTEM INFORMATION with real implementation
Before this commit, OpenBSC used templates for the SYSTEM INFO 1, 2, 3, 4, 5 and 6 messages. Those templates were patched in various places to reflect the network config like ARFCN. Now, we actually generate those SI messages ourselves, using values from the configuration file, and even calculating neighbor cell lists. All bts'es that you have configured in OpenBSC will end up in the neighbor cell list - which should be more than sufficient for the current small-single-site networks.
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/Makefile.am2
-rw-r--r--openbsc/src/abis_rsl.c10
-rw-r--r--openbsc/src/bitvec.c123
-rw-r--r--openbsc/src/bsc_init.c329
-rw-r--r--openbsc/src/paging.c2
-rw-r--r--openbsc/src/rest_octets.c393
-rw-r--r--openbsc/src/system_information.c427
-rw-r--r--openbsc/src/vty_interface.c7
8 files changed, 1006 insertions, 287 deletions
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index 4d18692db..f22582122 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -11,7 +11,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
- talloc_ctx.c
+ talloc_ctx.c system_information.c bitvec.c rest_octets.c
libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \
mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index b049c3c8a..1d41d2b5d 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -1729,11 +1729,11 @@ int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf)
/* From Table 10.5.33 of GSM 04.08 */
int rsl_number_of_paging_subchannels(struct gsm_bts *bts)
{
- if (bts->chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) {
- return MAX(1, (3 - bts->chan_desc.bs_ag_blks_res))
- * (bts->chan_desc.bs_pa_mfrms + 2);
+ if (bts->si_common.chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) {
+ return MAX(1, (3 - bts->si_common.chan_desc.bs_ag_blks_res))
+ * (bts->si_common.chan_desc.bs_pa_mfrms + 2);
} else {
- return (9 - bts->chan_desc.bs_ag_blks_res)
- * (bts->chan_desc.bs_pa_mfrms + 2);
+ return (9 - bts->si_common.chan_desc.bs_ag_blks_res)
+ * (bts->si_common.chan_desc.bs_pa_mfrms + 2);
}
}
diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c
new file mode 100644
index 000000000..ac2554475
--- /dev/null
+++ b/openbsc/src/bitvec.c
@@ -0,0 +1,123 @@
+/* bit vector utility routines */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <errno.h>
+#include <sys/types.h>
+
+#include <openbsc/bitvec.h>
+
+#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
+
+static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
+{
+ unsigned int bytenum = bitnum / 8;
+
+ return bytenum;
+}
+
+int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
+ enum bit_value bit)
+{
+ unsigned int bytenum = bytenum_from_bitnum(bitnr);
+ unsigned int bitnum = 7 - (bitnr % 8);
+ u_int8_t bitval;
+
+ if (bytenum >= bv->data_len)
+ return -EINVAL;
+
+ switch (bit) {
+ case ZERO:
+ bitval = (0 << bitnum);
+ break;
+ case ONE:
+ bitval = (1 << bitnum);
+ break;
+ case L:
+ bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
+ break;
+ case H:
+ bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* first clear the bit */
+ bv->data[bytenum] &= ~(1 << bitnum);
+
+ /* then set it to desired value */
+ bv->data[bytenum] |= bitval;
+
+ return 0;
+}
+
+int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
+{
+ int rc;
+
+ rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
+ if (!rc)
+ bv->cur_bit++;
+
+ return rc;
+}
+
+int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count)
+{
+ int i, rc;
+
+ for (i = 0; i < count; i++) {
+ rc = bitvec_set_bit(bv, bits[i]);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits)
+{
+ int i, rc;
+
+ for (i = 0; i < num_bits; i++) {
+ int bit = 0;
+ if (ui & (1 << (num_bits - i - 1)))
+ bit = 1;
+ rc = bitvec_set_bit(bv, bit);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+/* pad all remaining bits up to num_bits */
+int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
+{
+ unsigned int i;
+
+ for (i = bv->cur_bit; i <= up_to_bit; i++)
+ bitvec_set_bit(bv, L);
+
+ return 0;
+}
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index 153e024e4..d21f71a0c 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -28,6 +28,7 @@
#include <openbsc/debug.h>
#include <openbsc/misdn.h>
#include <openbsc/telnet_interface.h>
+#include <openbsc/system_information.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
#include <openbsc/talloc.h>
@@ -37,7 +38,6 @@ extern struct gsm_network *bsc_gsmnet;
extern int ipacc_rtp_direct;
static void patch_nm_tables(struct gsm_bts *bts);
-static void patch_si_tables(struct gsm_bts *bts);
/* The following definitions are for OM and NM packets that we cannot yet
* generate by code but we just pass on */
@@ -667,219 +667,42 @@ int bsc_shutdown_net(struct gsm_network *net)
return 0;
}
-struct bcch_info {
- u_int8_t type;
- u_int8_t len;
- const u_int8_t *data;
-};
-
-/*
-SYSTEM INFORMATION TYPE 1
- Cell channel description
- Format-ID bit map 0
- CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
- RACH Control Parameters
- maximum 7 retransmissions
- 8 slots used to spread transmission
- cell not barred for access
- call reestablishment not allowed
- Access Control Class = 0000
-*/
-static u_int8_t si1[] = {
- /* header */0x55, 0x06, 0x19,
- /* ccdesc */0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/,
- /* rach */0xD5, 0x04, 0x00,
- /* s1 reset*/0x2B
-};
-
-/*
- SYSTEM INFORMATION TYPE 2
- Neighbour Cells Description
- EXT-IND: Carries the complete BA
- BA-IND = 0
- Format-ID bit map 0
- CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- NCC permitted (NCC) = FF
- RACH Control Parameters
- maximum 7 retransmissions
- 8 slots used to spread transmission
- cell not barred for access
- call reestablishment not allowed
- Access Control Class = 0000
-*/
-static u_int8_t si2[] = {
- /* header */0x59, 0x06, 0x1A,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* ncc */0xFF,
- /* rach*/0xD5, 0x04, 0x00
-};
-
-/*
-SYSTEM INFORMATION TYPE 3
- Cell identity = 00001 (1h)
- Location area identification
- Mobile Country Code (MCC): 001
- Mobile Network Code (MNC): 01
- Location Area Code (LAC): 00001 (1h)
- Control Channel Description
- Attach-detach: MSs in the cell are not allowed to apply IMSI attach /detach
- 0 blocks reserved for access grant
- 1 channel used for CCCH, with SDCCH
- 5 multiframes period for PAGING REQUEST
- Time-out T3212 = 0
- Cell Options BCCH
- Power control indicator: not set
- MSs shall not use uplink DTX
- Radio link timeout = 36
- Cell Selection Parameters
- Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection
- max.TX power level MS may use for CCH = 2 <- according to GSM05.05 39dBm (max)
- Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters
- Half rate support (NECI): New establishment causes are not supported
- min.RX signal level for MS = 0
- RACH Control Parameters
- maximum 7 retransmissions
- 8 slots used to spread transmission
- cell not barred for access
- call reestablishment not allowed
- Access Control Class = 0000
- SI 3 Rest Octets (not present)
-*/
-static u_int8_t si3[] = {
- /* header */0x49, 0x06, 0x1B,
- /* cell */0x00, 0x01,
- /* lai */0x00, 0xF1, 0x10, 0x00, 0x01,
- /* desc */0x01, 0x03, 0x00,
- /* option*/0x28,
- /* selection*/0x62, 0x00,
- /* rach */0xD5, 0x04, 0x00,
- /* rest */ 0x2B, 0x2B, 0x2B, 0x2B
-};
-
-/*
-SYSTEM INFORMATION TYPE 4
- Location area identification
- Mobile Country Code (MCC): 001
- Mobile Network Code (MNC): 01
- Location Area Code (LAC): 00001 (1h)
- Cell Selection Parameters
- Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection
- max.TX power level MS may use for CCH = 2
- Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters
- Half rate support (NECI): New establishment causes are not supported
- min.RX signal level for MS = 0
- RACH Control Parameters
- maximum 7 retransmissions
- 8 slots used to spread transmission
- cell not barred for access
- call reestablishment not allowed
- Access Control Class = 0000
- CBCH Channel Description
- Type = SDCCH/4[2]
- Timeslot Number: 0
- Training Sequence Code: 7h
- ARFCN: 1
- SI Rest Octets (not present)
-*/
-static u_int8_t si4[] = {
- /* header */0x41, 0x06, 0x1C,
- /* lai */0x00, 0xF1, 0x10, 0x00, 0x01,
- /* sel */0x62, 0x00,
- /* rach*/0xD5, 0x04, 0x00,
- /* cbch chan desc */ 0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/,
- /* rest octets */ 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B
-};
-
-/*
- SYSTEM INFORMATION TYPE 5
- Neighbour Cells Description
- EXT-IND: Carries the complete BA
- BA-IND = 0
- Format-ID bit map 0
- CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-*/
-
-static u_int8_t si5[] = {
- /* header without l2 len*/0x06, 0x1D,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-// SYSTEM INFORMATION TYPE 6
-
-/*
-SACCH FILLING
- System Info Type: SYSTEM INFORMATION 6
- L3 Information (Hex): 06 1E 00 01 xx xx 10 00 01 28 FF
-
-SYSTEM INFORMATION TYPE 6
- Cell identity = 00001 (1h)
- Location area identification
- Mobile Country Code (MCC): 001
- Mobile Network Code (MNC): 01
- Location Area Code (LAC): 00001 (1h)
- Cell Options SACCH
- Power control indicator: not set
- MSs shall not use uplink DTX on a TCH-F. MS shall not use uplink DTX on TCH-H.
- Radio link timeout = 36
- NCC permitted (NCC) = FF
-*/
-
-static u_int8_t si6[] = {
- /* header */0x06, 0x1E,
- /* cell id*/ 0x00, 0x01,
- /* lai */ 0x00, 0xF1, 0x10, 0x00, 0x01,
- /* options */ 0x28,
- /* ncc */ 0xFF,
-};
-
-
-
-static const struct bcch_info bcch_infos[] = {
- {
- .type = RSL_SYSTEM_INFO_1,
- .len = sizeof(si1),
- .data = si1,
- }, {
- .type = RSL_SYSTEM_INFO_2,
- .len = sizeof(si2),
- .data = si2,
- }, {
- .type = RSL_SYSTEM_INFO_3,
- .len = sizeof(si3),
- .data = si3,
- }, {
- .type = RSL_SYSTEM_INFO_4,
- .len = sizeof(si4),
- .data = si4,
- },
-};
-
-static_assert(sizeof(si1) == sizeof(struct gsm48_system_information_type_1), type1)
-static_assert(sizeof(si2) == sizeof(struct gsm48_system_information_type_2), type2)
-static_assert(sizeof(si3) == sizeof(struct gsm48_system_information_type_3), type3)
-static_assert(sizeof(si4) >= sizeof(struct gsm48_system_information_type_4), type4)
-static_assert(sizeof(si5) == sizeof(struct gsm48_system_information_type_5), type5)
-static_assert(sizeof(si6) >= sizeof(struct gsm48_system_information_type_6), type6)
-
/* set all system information types */
static int set_system_infos(struct gsm_bts_trx *trx)
{
- int i;
+ int i, rc;
+ u_int8_t si_tmp[23];
if (trx == trx->bts->c0) {
- for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) {
- rsl_bcch_info(trx, bcch_infos[i].type,
- bcch_infos[i].data,
- bcch_infos[i].len);
+ for (i = 1; i <= 4; i++) {
+ rc = gsm_generate_si(si_tmp, trx->bts, i);
+ if (rc < 0)
+ goto err_out;
+ rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp));
}
}
- rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5));
- rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6));
+#ifdef GPRS
+ rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13);
+ if (rc < 0)
+ goto err_out;
+ rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc);
+#endif
+ rc = gsm_generate_si(si_tmp, trx->bts, 5);
+ if (rc < 0)
+ goto err_out;
+ rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si_tmp, rc);
+
+ rc = gsm_generate_si(si_tmp, trx->bts, 6);
+ if (rc < 0)
+ goto err_out;
+ rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc);
return 0;
+err_out:
+ fprintf(stderr, "Cannot generate SI for BTS %u, most likely "
+ "a problem with neighbor cell list generation\n",
+ trx->bts->nr);
+ return rc;
}
/*
@@ -913,81 +736,12 @@ static void patch_nm_tables(struct gsm_bts *bts)
nanobts_attr_radio[1] = bts->c0->max_power_red / 2;
}
-/*
- * Patch the various SYSTEM INFORMATION tables to update
- * the LAI
- */
-static void patch_si_tables(struct gsm_bts *bts)
-{
- u_int8_t arfcn_low = bts->c0->arfcn & 0xff;
- u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f;
-
- /* covert the raw packet to the struct */
- struct gsm48_system_information_type_1 *type_1 =
- (struct gsm48_system_information_type_1*)&si1;
- struct gsm48_system_information_type_2 *type_2 =
- (struct gsm48_system_information_type_2*)&si2;
- struct gsm48_system_information_type_3 *type_3 =
- (struct gsm48_system_information_type_3*)&si3;
- struct gsm48_system_information_type_4 *type_4 =
- (struct gsm48_system_information_type_4*)&si4;
- struct gsm48_system_information_type_6 *type_6 =
- (struct gsm48_system_information_type_6*)&si6;
- struct gsm48_loc_area_id lai;
-
- gsm0408_generate_lai(&lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
-
- /* assign the MCC and MNC */
- type_3->lai = lai;
- type_4->lai = lai;
- type_6->lai = lai;
-
- /* set the CI */
- type_3->cell_identity = htons(bts->cell_identity);
- type_6->cell_identity = htons(bts->cell_identity);
-
- type_4->data[2] &= 0xf0;
- type_4->data[2] |= arfcn_high;
- type_4->data[3] = arfcn_low;
-
- /* patch Control Channel Description 10.5.2.11 */
- type_3->control_channel_desc = bts->chan_desc;
-
- /* patch TSC */
- si4[15] &= ~0xe0;
- si4[15] |= (bts->tsc & 7) << 5;
-
- /* patch MS max power for CCH */
- type_4->cell_sel_par.ms_txpwr_max_ccch =
- ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
-
- /* Set NECI to influence channel request */
- type_3->cell_sel_par.neci = bts->network->neci;
- type_4->cell_sel_par.neci = bts->network->neci;
-
- if (bts->cell_barred) {
- type_1->rach_control.cell_bar = 1;
- type_2->rach_control.cell_bar = 1;
- type_3->rach_control.cell_bar = 1;
- type_4->rach_control.cell_bar = 1;
- } else {
- type_1->rach_control.cell_bar = 0;
- type_2->rach_control.cell_bar = 0;
- type_3->rach_control.cell_bar = 0;
- type_4->rach_control.cell_bar = 0;
- }
-}
-
-
static void bootstrap_rsl(struct gsm_bts_trx *trx)
{
fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) "
"using MCC=%u MNC=%u BSIC=%u TSC=%u\n",
trx->bts->nr, trx->nr, bsc_gsmnet->country_code,
bsc_gsmnet->network_code, trx->bts->bsic, trx->bts->tsc);
- patch_si_tables(trx->bts);
set_system_infos(trx);
}
@@ -1042,11 +796,32 @@ static int bootstrap_bts(struct gsm_bts *bts)
}
/* Control Channel Description */
- bts->chan_desc.att = 1;
- bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
- bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
+ bts->si_common.chan_desc.att = 1;
+ bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
+ bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
+ if (bts->cell_barred)
+ bts->si_common.rach_control.cell_bar = 1;
/* T3212 is set from vty/config */
+ /* some defaults for our system information */
+ bts->si_common.rach_control.re = 1; /* no re-establishment */
+ bts->si_common.rach_control.tx_integer = 5; /* 8 slots spread */
+ bts->si_common.rach_control.max_trans = 3; /* 7 retransmissions */
+ bts->si_common.rach_control.t2 = 4; /* no emergency calls */
+
+ bts->si_common.cell_options.radio_link_timeout = 2; /* 12 */
+ bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */
+ bts->si_common.cell_options.pwrc = 0; /* PWRC not set */
+
+ bts->si_common.cell_sel_par.ms_txpwr_max_ccch =
+ ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
+ bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */
+ bts->si_common.cell_sel_par.rxlev_acc_min = 0;
+ bts->si_common.cell_sel_par.acs = 0;
+ bts->si_common.cell_sel_par.neci = bts->network->neci;
+
+ bts->si_common.ncc_permitted = 0xff;
+
paging_init(bts);
return 0;
diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c
index fe6ea52d1..b273419c3 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -55,7 +55,7 @@ static unsigned int calculate_group(struct gsm_bts *bts, struct gsm_subscriber *
int blocks;
unsigned int group;
- ccch_conf = bts->chan_desc.ccch_conf;
+ ccch_conf = bts->si_common.chan_desc.ccch_conf;
bs_cc_chans = rsl_ccch_conf_to_bs_cc_chans(ccch_conf);
/* code word + 2, as 2 channels equals 0x0 */
blocks = rsl_number_of_paging_subchannels(bts);
diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c
new file mode 100644
index 000000000..6efd47515
--- /dev/null
+++ b/openbsc/src/rest_octets.c
@@ -0,0 +1,393 @@
+/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface,
+ * rest octet handling according to
+ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/bitvec.h>
+#include <openbsc/rest_octets.h>
+
+/* generate SI1 rest octets */
+int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
+{
+ struct bitvec bv;
+
+ memset(&bv, 0, sizeof(bv));
+ bv.data = data;
+ bv.data_len = 2;
+
+ if (nch_pos) {
+ bitvec_set_bit(&bv, H);
+ bitvec_set_uint(&bv, *nch_pos, 5);
+ } else
+ bitvec_set_bit(&bv, L);
+
+ bitvec_spare_padding(&bv, 15);
+ return 0;
+}
+
+/* Append selection parameters to bitvec */
+static void append_selection_params(struct bitvec *bv,
+ const struct gsm48_si_selection_params *sp)
+{
+ if (sp->present) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_bit(bv, sp->cbq);
+ bitvec_set_uint(bv, sp->cell_resel_off, 6);
+ bitvec_set_uint(bv, sp->temp_offs, 3);
+ bitvec_set_uint(bv, sp->penalty_time, 5);
+ } else
+ bitvec_set_bit(bv, L);
+}
+
+/* Append power offset to bitvec */
+static void append_power_offset(struct bitvec *bv,
+ const struct gsm48_si_power_offset *po)
+{
+ if (po->present) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, po->power_offset, 2);
+ } else
+ bitvec_set_bit(bv, L);
+}
+
+/* Append GPRS indicator to bitvec */
+static void append_gprs_ind(struct bitvec *bv,
+ const struct gsm48_si3_gprs_ind *gi)
+{
+ if (gi->present) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, gi->ra_colour, 3);
+ /* 0 == SI13 in BCCH Norm, 1 == SI13 sent on BCCH Ext */
+ bitvec_set_bit(bv, gi->si13_position);
+ } else
+ bitvec_set_bit(bv, L);
+}
+
+
+/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */
+int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3)
+{
+ struct bitvec bv;
+
+ memset(&bv, 0, sizeof(bv));
+ bv.data = data;
+ bv.data_len = 5;
+
+ /* Optional Selection Parameters */
+ append_selection_params(&bv, &si3->selection_params);
+
+ /* Optional Power Offset */
+ append_power_offset(&bv, &si3->power_offset);
+
+ /* Do we have a SI2ter on the BCCH? */
+ if (si3->si2ter_indicator)
+ bitvec_set_bit(&bv, H);
+ else
+ bitvec_set_bit(&bv, L);
+
+ /* Early Classmark Sending Control */
+ if (si3->early_cm_ctrl)
+ bitvec_set_bit(&bv, H);
+ else
+ bitvec_set_bit(&bv, L);
+
+ /* Do we have a SI Type 9 on the BCCH? */
+ if (si3->scheduling.present) {
+ bitvec_set_bit(&bv, H);
+ bitvec_set_uint(&bv, si3->scheduling.where, 3);
+ } else
+ bitvec_set_bit(&bv, L);
+
+ /* GPRS Indicator */
+ append_gprs_ind(&bv, &si3->gprs_ind);
+
+ return bitvec_spare_padding(&bv, (bv.data_len*8)-1);
+}
+
+static int append_lsa_params(struct bitvec *bv,
+ const struct gsm48_lsa_params *lsa_params)
+{
+ /* FIXME */
+}
+
+/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
+int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4)
+{
+ struct bitvec bv;
+
+ memset(&bv, 0, sizeof(bv));
+ bv.data = data;
+ bv.data_len = 11; /* FIXME: up to ? */
+
+ /* SI4 Rest Octets O */
+ append_selection_params(&bv, &si4->selection_params);
+ append_power_offset(&bv, &si4->power_offset);
+ append_gprs_ind(&bv, &si4->gprs_ind);
+
+ if (0 /* FIXME */) {
+ /* H and SI4 Rest Octets S */
+ bitvec_set_bit(&bv, H);
+
+ /* LSA Parameters */
+ if (si4->lsa_params.present) {
+ bitvec_set_bit(&bv, H);
+ append_lsa_params(&bv, &si4->lsa_params);
+ } else
+ bitvec_set_bit(&bv, L);
+
+ /* Cell Identity */
+ if (1) {
+ bitvec_set_bit(&bv, H);
+ bitvec_set_uint(&bv, si4->cell_id, 16);
+ } else
+ bitvec_set_bit(&bv, L);
+
+ /* LSA ID Information */
+ if (0) {
+ bitvec_set_bit(&bv, H);
+ /* FIXME */
+ } else
+ bitvec_set_bit(&bv, L);
+ } else {
+ /* L and break indicator */
+ bitvec_set_bit(&bv, L);
+ bitvec_set_bit(&bv, si4->break_ind ? H : L);
+ }
+
+ return 0;
+}
+
+/* GPRS Mobile Allocation as per TS 04.60 Chapter 12.10a:
+ < GPRS Mobile Allocation IE > ::=
+ < HSN : bit (6) >
+ { 0 | 1 < RFL number list : < RFL number list struct > > }
+ { 0 < MA_LENGTH : bit (6) >
+ < MA_BITMAP: bit (val(MA_LENGTH) + 1) >
+ | 1 { 0 | 1 <ARFCN index list : < ARFCN index list struct > > } } ;
+
+ < RFL number list struct > :: =
+ < RFL_NUMBER : bit (4) >
+ { 0 | 1 < RFL number list struct > } ;
+ < ARFCN index list struct > ::=
+ < ARFCN_INDEX : bit(6) >
+ { 0 | 1 < ARFCN index list struct > } ;
+ */
+static int append_gprs_mobile_alloc(struct bitvec *bv)
+{
+ /* Hopping Sequence Number */
+ bitvec_set_uint(bv, 0, 6);
+
+ if (0) {
+ /* We want to use a RFL number list */
+ bitvec_set_bit(bv, 1);
+ /* FIXME: RFL number list */
+ } else
+ bitvec_set_bit(bv, 0);
+
+ if (0) {
+ /* We want to use a MA_BITMAP */
+ bitvec_set_bit(bv, 0);
+ /* FIXME: MA_LENGTH, MA_BITMAP, ... */
+ } else {
+ bitvec_set_bit(bv, 1);
+ if (0) {
+ /* We want to provide an ARFCN index list */
+ bitvec_set_bit(bv, 1);
+ /* FIXME */
+ } else
+ bitvec_set_bit(bv, 0);
+ }
+ return 0;
+}
+
+static int encode_t3192(unsigned int t3192)
+{
+ if (t3192 == 0)
+ return 3;
+ else if (t3192 <= 80)
+ return 4;
+ else if (t3192 <= 120)
+ return 5;
+ else if (t3192 <= 160)
+ return 6;
+ else if (t3192 <= 200)
+ return 7;
+ else if (t3192 <= 500)
+ return 0;
+ else if (t3192 <= 1000)
+ return 1;
+ else if (t3192 <= 1500)
+ return 2;
+ else
+ return -EINVAL;
+}
+
+static int encode_drx_timer(unsigned int drx)
+{
+ if (drx == 0)
+ return 0;
+ else if (drx == 1)
+ return 1;
+ else if (drx == 2)
+ return 2;
+ else if (drx <= 4)
+ return 3;
+ else if (drx <= 8)
+ return 4;
+ else if (drx <= 16)
+ return 5;
+ else if (drx <= 32)
+ return 6;
+ else if (drx <= 64)
+ return 7;
+ else
+ return -EINVAL;
+}
+
+/* GPRS Cell Options as per TS 04.60 Chapter 12.24
+ < GPRS Cell Options IE > ::=
+ < NMO : bit(2) >
+ < T3168 : bit(3) >
+ < T3192 : bit(3) >
+ < DRX_TIMER_MAX: bit(3) >
+ < ACCESS_BURST_TYPE: bit >
+ < CONTROL_ACK_TYPE : bit >
+ < BS_CV_MAX: bit(4) >
+ { 0 | 1 < PAN_DEC : bit(3) >
+ < PAN_INC : bit(3) >
+ < PAN_MAX : bit(3) >
+ { 0 | 1 < Extension Length : bit(6) >
+ < bit (val(Extension Length) + 1
+ & { < Extension Information > ! { bit ** = <no string> } } ;
+ < Extension Information > ::=
+ { 0 | 1 < EGPRS_PACKET_CHANNEL_REQUEST : bit >
+ < BEP_PERIOD : bit(4) > }
+ < PFC_FEATURE_MODE : bit >
+ < DTM_SUPPORT : bit >
+ <BSS_PAGING_COORDINATION: bit >
+ <spare bit > ** ;
+ */
+static int append_gprs_cell_opt(struct bitvec *bv, struct gprs_cell_options *gco)
+{
+ int t3192, drx_timer_max;
+
+ t3192 = encode_t3192(gco->t3192);
+ if (t3192 < 0)
+ return t3192;
+
+ drx_timer_max = encode_drx_timer(gco->drx_timer_max);
+ if (drx_timer_max < 0)
+ return drx_timer_max;
+
+ bitvec_set_uint(bv, gco->nmo, 2);
+ bitvec_set_uint(bv, gco->t3168 / 500, 3);
+ bitvec_set_uint(bv, t3192, 3);
+ bitvec_set_uint(bv, drx_timer_max, 3);
+ /* ACCESS_BURST_TYPE: Hard-code 8bit */
+ bitvec_set_bit(bv, 0);
+ /* CONTROL_ACK_TYPE: Hard-code to RLC/MAC control block */
+ bitvec_set_bit(bv, 1);
+ bitvec_set_uint(bv, gco->bs_cv_max, 4);
+
+ /* hard-code no PAN_{DEC,INC,MAX} */
+ bitvec_set_bit(bv, 0);
+
+ /* no extension information (EDGE) */
+ bitvec_set_bit(bv, 0);
+
+ return 0;
+}
+
+static void append_gprs_pwr_ctrl_pars(struct bitvec *bv,
+ struct gprs_power_ctrl_pars *pcp)
+{
+ bitvec_set_uint(bv, pcp->alpha, 4);
+ bitvec_set_uint(bv, pcp->t_avg_w, 5);
+ bitvec_set_uint(bv, pcp->t_avg_t, 5);
+ bitvec_set_uint(bv, pcp->pc_meas_chan, 1);
+ bitvec_set_uint(bv, pcp->n_avg_i, 4);
+}
+
+/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */
+int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
+{
+ struct bitvec bv;
+
+ memset(&bv, 0, sizeof(bv));
+ bv.data = data;
+ bv.data_len = 21;
+
+ if (0) {
+ /* No rest octets */
+ bitvec_set_bit(&bv, L);
+ } else {
+ bitvec_set_bit(&bv, H);
+ bitvec_set_uint(&bv, si13->bcch_change_mark, 3);
+ bitvec_set_uint(&bv, si13->si_change_field, 4);
+ if (0) {
+ bitvec_set_bit(&bv, 0);
+ } else {
+ bitvec_set_bit(&bv, 1);
+ bitvec_set_uint(&bv, si13->bcch_change_mark, 2);
+ append_gprs_mobile_alloc(&bv);
+ }
+ if (!si13->pbcch_present) {
+ /* PBCCH not present in cell */
+ bitvec_set_bit(&bv, 0);
+ bitvec_set_uint(&bv, si13->no_pbcch.rac, 8);
+ bitvec_set_bit(&bv, si13->no_pbcch.spgc_ccch_sup);
+ bitvec_set_uint(&bv, si13->no_pbcch.prio_acc_thr, 3);
+ bitvec_set_uint(&bv, si13->no_pbcch.net_ctrl_ord, 2);
+ append_gprs_cell_opt(&bv, &si13->cell_opts);
+ append_gprs_pwr_ctrl_pars(&bv, &si13->pwr_ctrl_pars);
+ } else {
+ /* PBCCH present in cell */
+ bitvec_set_bit(&bv, 1);
+ bitvec_set_uint(&bv, si13->pbcch.psi1_rep_per, 4);
+ /* PBCCH Descripiton */
+ bitvec_set_uint(&bv, si13->pbcch.pb, 4);
+ bitvec_set_uint(&bv, si13->pbcch.tsc, 3);
+ bitvec_set_uint(&bv, si13->pbcch.tn, 3);
+ switch (si13->pbcch.carrier_type) {
+ case PBCCH_BCCH:
+ bitvec_set_bit(&bv, 0);
+ bitvec_set_bit(&bv, 0);
+ break;
+ case PBCCH_ARFCN:
+ bitvec_set_bit(&bv, 0);
+ bitvec_set_bit(&bv, 1);
+ bitvec_set_uint(&bv, si13->pbcch.arfcn, 10);
+ break;
+ case PBCCH_MAIO:
+ bitvec_set_bit(&bv, 1);
+ bitvec_set_uint(&bv, si13->pbcch.maio, 6);
+ break;
+ }
+ }
+ }
+ return bitvec_spare_padding(&bv, (bv.data_len*8)-1);
+}
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
new file mode 100644
index 000000000..d6d166c79
--- /dev/null
+++ b/openbsc/src/system_information.c
@@ -0,0 +1,427 @@
+/* GSM 04.08 System Information (SI) encoding and decoding
+ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
+
+/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <openbsc/gsm_04_08.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/abis_rsl.h>
+#include <openbsc/rest_octets.h>
+
+#define GSM48_CELL_CHAN_DESC_SIZE 16
+#define GSM_MACBLOCK_LEN 23
+#define GSM_MACBLOCK_PADDING 0x2b
+
+static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
+{
+ unsigned int byte, bit;
+
+ if (arfcn > 124)
+ return -EINVAL;
+
+ byte = arfcn / 8;
+ bit = arfcn % 8;
+
+ chan_list[GSM48_CELL_CHAN_DESC_SIZE-byte] |= (1 << bit);
+
+ return 0;
+}
+
+static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
+{
+ unsigned int byte, bit;
+ unsigned int min_arfcn;
+ unsigned int bitno;
+
+ min_arfcn = (chan_list[0] & 1) << 9;
+ min_arfcn |= chan_list[1] << 1;
+ min_arfcn |= (chan_list[2] >> 7) & 1;
+
+ /* The lower end of our bitmaks is always implicitly included */
+ if (arfcn == min_arfcn)
+ return 0;
+
+ if (arfcn < min_arfcn)
+ return -EINVAL;
+ if (arfcn > min_arfcn + 111)
+ return -EINVAL;
+
+ bitno = (arfcn - min_arfcn);
+ byte = bitno / 8;
+ bit = bitno % 8;
+
+ chan_list[2 + byte] |= 1 << (7 - bit);
+
+ return 0;
+}
+
+/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
+static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+ int rc, min = 1024, max = 0;
+
+ memset(chan_list, 0, 16);
+
+ /* GSM900-only handsets only support 'bit map 0 format' */
+ if (bts->band == GSM_BAND_900) {
+ chan_list[0] = 0;
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+ }
+
+ /* We currently only support the 'Variable bitmap format' */
+ chan_list[0] = 0x8e;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->arfcn < min)
+ min = trx->arfcn;
+ if (trx->arfcn > max)
+ max = trx->arfcn;
+ }
+
+ if ((max - min) > 111)
+ return -EINVAL;
+
+ chan_list[0] |= (min >> 9) & 1;
+ chan_list[1] = (min >> 1);
+ chan_list[2] = (min & 1) << 7;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+
+/* 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, const struct gsm_bts *bts)
+{
+ struct gsm_bts *cur_bts;
+ struct gsm_bts_trx *trx;
+ int rc, min = 1024, max = 0;
+
+ memset(chan_list, 0, 16);
+
+ /* GSM900-only handsets only support 'bit map 0 format' */
+ if (bts->band == GSM_BAND_900) {
+ chan_list[0] = 0;
+ llist_for_each_entry(cur_bts, &bts->list, list) {
+ trx = cur_bts->c0;
+ rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+ }
+
+ /* We currently only support the 'Variable bitmap format' */
+ chan_list[0] = 0x8e;
+
+ llist_for_each_entry(cur_bts, &bts->list, list) {
+ if (&cur_bts->list == &bts->network->bts_list)
+ continue;
+ trx = cur_bts->c0;
+ if (trx->arfcn < min)
+ min = trx->arfcn;
+ if (trx->arfcn > max)
+ max = trx->arfcn;
+ }
+
+ if ((max - min) > 111)
+ return -EINVAL;
+
+ chan_list[0] |= (min >> 9) & 1;
+ chan_list[1] = (min >> 1);
+ chan_list[2] = (min & 1) << 7;
+
+ llist_for_each_entry(cur_bts, &bts->list, list) {
+ if (&cur_bts->list == &bts->network->bts_list)
+ continue;
+ trx = cur_bts->c0;
+ rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int generate_si1(u_int8_t *output, const struct gsm_bts *bts)
+{
+ int rc;
+ struct gsm48_system_information_type_1 *si1 =
+ (struct gsm48_system_information_type_1 *) output;
+
+ memset(si1, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ si1->header.l2_plen = (21 << 2) | 1;
+ si1->header.rr_protocol_discriminator = GSM48_PDISC_RR;
+ si1->header.skip_indicator = 0;
+ si1->header.system_information = GSM48_MT_RR_SYSINFO_1;
+
+ rc = generate_cell_chan_list(si1->cell_channel_description, bts);
+ if (rc < 0)
+ return rc;
+
+ si1->rach_control = bts->si_common.rach_control;
+
+ /* SI1 Rest Octets (10.5.2.32), contains NCH position */
+ rest_octets_si1(si1->rest_octets, NULL);
+
+ return GSM_MACBLOCK_LEN;
+}
+
+static int generate_si2(u_int8_t *output, const struct gsm_bts *bts)
+{
+ int rc;
+ struct gsm48_system_information_type_2 *si2 =
+ (struct gsm48_system_information_type_2 *) output;
+
+ memset(si2, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ si2->header.l2_plen = (22 << 2) | 1;
+ si2->header.rr_protocol_discriminator = GSM48_PDISC_RR;
+ si2->header.skip_indicator = 0;
+ si2->header.system_information = GSM48_MT_RR_SYSINFO_2;
+
+ rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts);
+ if (rc < 0)
+ return rc;
+
+ si2->ncc_permitted = bts->si_common.ncc_permitted;
+ si2->rach_control = bts->si_common.rach_control;
+
+ return GSM_MACBLOCK_LEN;
+}
+
+struct gsm48_si_ro_info si_info = {
+ .selection_params = {
+ .present = 0,
+ },
+ .power_offset = {
+ .present = 0,
+ },
+ .si2ter_indicator = 0,
+ .early_cm_ctrl = 1,
+ .scheduling = {
+ .present = 0,
+ },
+ .gprs_ind = {
+ .si13_position = 0,
+ .ra_colour = 0,
+ .present = 0,
+ },
+ .lsa_params = {
+ .present = 0,
+ },
+ .cell_id = 0, /* FIXME: doesn't the bts have this? */
+ .break_ind = 0,
+};
+
+static int generate_si3(u_int8_t *output, const struct gsm_bts *bts)
+{
+ struct gsm48_system_information_type_3 *si3 =
+ (struct gsm48_system_information_type_3 *) output;
+
+ memset(si3, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ si3->header.l2_plen = (18 << 2) | 1;
+ si3->header.rr_protocol_discriminator = GSM48_PDISC_RR;
+ si3->header.skip_indicator = 0;
+ si3->header.system_information = GSM48_MT_RR_SYSINFO_3;
+
+ si3->cell_identity = htons(bts->cell_identity);
+ gsm0408_generate_lai(&si3->lai, bts->network->country_code,
+ bts->network->network_code,
+ bts->location_area_code);
+ si3->control_channel_desc = bts->si_common.chan_desc;
+ si3->cell_options = bts->si_common.cell_options;
+ si3->cell_sel_par = bts->si_common.cell_sel_par;
+ si3->rach_control = bts->si_common.rach_control;
+
+ /* SI3 Rest Octets (10.5.2.34), containing
+ CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME
+ Power Offset, 2ter Indicator, Early Classmark Sending,
+ Scheduling if and WHERE, GPRS Indicator, SI13 position */
+ rest_octets_si3(si3->rest_octets, &si_info);
+
+ return GSM_MACBLOCK_LEN;
+}
+
+static int generate_si4(u_int8_t *output, const struct gsm_bts *bts)
+{
+ struct gsm48_system_information_type_4 *si4 =
+ (struct gsm48_system_information_type_4 *) output;
+
+ /* length of all IEs present except SI4 rest octets and l2_plen */
+ int l2_plen = sizeof(*si4) - 1;
+
+ memset(si4, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ si4->header.rr_protocol_discriminator = GSM48_PDISC_RR;
+ si4->header.skip_indicator = 0;
+ si4->header.system_information = GSM48_MT_RR_SYSINFO_4;
+
+ gsm0408_generate_lai(&si4->lai, bts->network->country_code,
+ bts->network->network_code,
+ bts->location_area_code);
+ si4->cell_sel_par = bts->si_common.cell_sel_par;
+ si4->rach_control = bts->si_common.rach_control;
+
+ /* Optional: CBCH Channel Description + CBCH Mobile Allocation */
+
+ si4->header.l2_plen = (l2_plen << 2) | 1;
+
+ /* SI4 Rest Octets (10.5.2.35), containing
+ Optional Power offset, GPRS Indicator,
+ Cell Identity, LSA ID, Selection Parameter */
+ rest_octets_si4(si4->data, &si_info);
+
+ return GSM_MACBLOCK_LEN;
+}
+
+static int generate_si5(u_int8_t *output, const struct gsm_bts *bts)
+{
+ struct gsm48_system_information_type_5 *si5 =
+ (struct gsm48_system_information_type_5 *) output;
+ int rc;
+
+ memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ /* l2 pseudo length, not part of msg: 18 */
+ 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);
+ if (rc < 0)
+ return rc;
+
+ /* 04.08 9.1.37: L2 Pseudo Length of 18 */
+ return 18;
+}
+
+static int generate_si6(u_int8_t *output, const struct gsm_bts *bts)
+{
+ struct gsm48_system_information_type_6 *si6 =
+ (struct gsm48_system_information_type_6 *) output;
+
+ memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ /* l2 pseudo length, not part of msg: 11 */
+ si6->rr_protocol_discriminator = GSM48_PDISC_RR;
+ si6->skip_indicator = 0;
+ si6->system_information = GSM48_MT_RR_SYSINFO_6;
+ si6->cell_identity = htons(bts->cell_identity);
+ gsm0408_generate_lai(&si6->lai, bts->network->country_code,
+ bts->network->network_code,
+ bts->location_area_code);
+ si6->cell_options = bts->si_common.cell_options;
+ si6->ncc_permitted = bts->si_common.ncc_permitted;
+
+ /* SI6 Rest Octets: 10.5.2.35a: PCH / NCH info, VBS/VGCS options */
+
+ return 18;
+}
+
+static struct gsm48_si13_info si13_default = {
+ .cell_opts = {
+ .nmo = GPRS_NMO_III,
+ .t3168 = 1000,
+ .t3192 = 1000,
+ .drx_timer_max = 1,
+ .bs_cv_max = 15,
+ },
+ .pwr_ctrl_pars = {
+ .alpha = 10, /* a = 1.0 */
+ .t_avg_w = 25,
+ .t_avg_t = 25,
+ .pc_meas_chan = 0, /* downling measured on CCCH */
+ .n_avg_i = 15,
+ },
+ .bcch_change_mark = 0,
+ .si_change_field = 0,
+ .pbcch_present = 0,
+ {
+ .no_pbcch = {
+ .rac = 0,
+ .spgc_ccch_sup = 0,
+ .net_ctrl_ord = 0,
+ .prio_acc_thr = 0,
+ },
+ },
+};
+
+static int generate_si13(u_int8_t *output, const struct gsm_bts *bts)
+{
+ struct gsm48_system_information_type_13 *si13 =
+ (struct gsm48_system_information_type_13 *) output;
+ int ret;
+
+ memset(si13, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
+
+ si13->header.rr_protocol_discriminator = GSM48_PDISC_RR;
+ si13->header.skip_indicator = 0;
+ si13->header.system_information = GSM48_MT_RR_SYSINFO_13;
+
+ ret = rest_octets_si13(si13->rest_octets, &si13_default);
+ if (ret < 0)
+ return ret;
+
+ si13->header.l2_plen = ret & 0xff;
+
+ return GSM_MACBLOCK_LEN;
+}
+
+int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type)
+{
+ switch (type) {
+ case RSL_SYSTEM_INFO_1:
+ return generate_si1(output, bts);
+ case RSL_SYSTEM_INFO_2:
+ return generate_si2(output, bts);
+ case RSL_SYSTEM_INFO_3:
+ return generate_si3(output, bts);
+ case RSL_SYSTEM_INFO_4:
+ return generate_si4(output, bts);
+ case RSL_SYSTEM_INFO_5:
+ return generate_si5(output, bts);
+ case RSL_SYSTEM_INFO_6:
+ return generate_si6(output, bts);
+ case RSL_SYSTEM_INFO_13:
+ return generate_si13(output, bts);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 066dfd5a9..3b150b2ea 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -234,9 +234,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
- if (bts->chan_desc.t3212)
+ if (bts->si_common.chan_desc.t3212)
vty_out(vty, " periodic location update %u%s",
- bts->chan_desc.t3212 * 10, VTY_NEWLINE);
+ bts->si_common.chan_desc.t3212 * 10, VTY_NEWLINE);
vty_out(vty, " channel allocator %s%s",
bts->chan_alloc_reverse ? "descending" : "ascending",
VTY_NEWLINE);
@@ -951,6 +951,7 @@ DEFUN(cfg_bts_lac,
return CMD_SUCCESS;
}
+
DEFUN(cfg_bts_tsc,
cfg_bts_tsc_cmd,
"training_sequence_code <0-255>",
@@ -1094,7 +1095,7 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd,
{
struct gsm_bts *bts = vty->index;
- bts->chan_desc.t3212 = atoi(argv[0]) / 10;
+ bts->si_common.chan_desc.t3212 = atoi(argv[0]) / 10;
return CMD_SUCCESS;
}