aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
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
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')
-rw-r--r--openbsc/include/openbsc/bitvec.h59
-rw-r--r--openbsc/include/openbsc/gsm_04_08.h23
-rw-r--r--openbsc/include/openbsc/gsm_data.h11
-rw-r--r--openbsc/include/openbsc/rest_octets.h122
-rw-r--r--openbsc/include/openbsc/system_information.h6
-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
13 files changed, 1220 insertions, 294 deletions
diff --git a/openbsc/include/openbsc/bitvec.h b/openbsc/include/openbsc/bitvec.h
new file mode 100644
index 000000000..80ed4ad0a
--- /dev/null
+++ b/openbsc/include/openbsc/bitvec.h
@@ -0,0 +1,59 @@
+#ifndef _BITVEC_H
+#define _BITVEC_H
+
+/* 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.
+ *
+ */
+
+
+/* In GSM mac blocks, every bit can be 0 or 1, or L or H. L/H are
+ * defined relative to the 0x2b padding pattern */
+enum bit_value {
+ ZERO = 0,
+ ONE = 1,
+ L = 2,
+ H = 3,
+};
+
+struct bitvec {
+ unsigned int cur_bit; /* curser to the next unused bit */
+ unsigned int data_len; /* length of data array in bytes */
+ u_int8_t *data; /* pointer to data array */
+};
+
+/* Set a bit at given position */
+int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
+ enum bit_value bit);
+
+/* Set the next bit in the vector */
+int bitvec_set_bit(struct bitvec *bv, enum bit_value bit);
+
+/* Set multiple bits at the current position */
+int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count);
+
+/* Add an unsigned integer (of length count bits) to current position */
+int bitvec_set_uint(struct bitvec *bv, unsigned int in, int count);
+
+
+/* Pad the bit vector up to a certain bit position */
+int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit);
+
+#endif /* _BITVEC_H */
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 4a5cebf46..a3b77a8ab 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -187,6 +187,13 @@ struct gsm48_control_channel_descr {
u_int8_t t3212;
} __attribute__ ((packed));
+struct gsm48_cell_options {
+ u_int8_t radio_link_timeout:4,
+ dtx:2,
+ pwrc:1,
+ spare:1;
+} __attribute__ ((packed));
+
/* Section 9.2.9 CM service request */
struct gsm48_service_request {
u_int8_t cm_service_type : 4,
@@ -203,7 +210,7 @@ struct gsm48_system_information_type_1 {
struct gsm48_system_information_type_header header;
u_int8_t cell_channel_description[16];
struct gsm48_rach_control rach_control;
- u_int8_t s1_reset;
+ u_int8_t rest_octets[0]; /* NCH position on the CCCH */
} __attribute__ ((packed));
/* Section 9.1.32 System information Type 2 */
@@ -220,10 +227,10 @@ struct gsm48_system_information_type_3 {
u_int16_t cell_identity;
struct gsm48_loc_area_id lai;
struct gsm48_control_channel_descr control_channel_desc;
- u_int8_t cell_options;
+ struct gsm48_cell_options cell_options;
struct gsm48_cell_sel_par cell_sel_par;
struct gsm48_rach_control rach_control;
- u_int8_t s3_reset_octets[4];
+ u_int8_t rest_octets[0];
} __attribute__ ((packed));
/* Section 9.1.36 System information Type 4 */
@@ -253,9 +260,15 @@ struct gsm48_system_information_type_6 {
u_int8_t system_information;
u_int16_t cell_identity;
struct gsm48_loc_area_id lai;
- u_int8_t cell_options;
+ struct gsm48_cell_options cell_options;
u_int8_t ncc_permitted;
- u_int8_t si_6_reset[0];
+ u_int8_t rest_octets[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.43a System Information type 13 */
+struct gsm48_system_information_type_13 {
+ struct gsm48_system_information_type_header header;
+ u_int8_t rest_octets[0];
} __attribute__ ((packed));
/* Section 9.2.12 IMSI Detach Indication */
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index b4a8ef550..fcd623fe6 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -356,8 +356,6 @@ struct gsm_bts {
/* number of this BTS on given E1 link */
u_int8_t bts_nr;
- struct gsm48_control_channel_descr chan_desc;
-
/* paging state and control */
struct gsm_bts_paging_state paging;
@@ -368,6 +366,15 @@ struct gsm_bts {
struct gsm_nm_state nm_state;
} site_mgr;
+ /* parameters from which we build SYSTEM INFORMATION */
+ struct {
+ struct gsm48_rach_control rach_control;
+ u_int8_t ncc_permitted;
+ struct gsm48_cell_sel_par cell_sel_par;
+ struct gsm48_cell_options cell_options;
+ struct gsm48_control_channel_descr chan_desc;
+ } si_common;
+
/* ip.accesss Unit ID's have Site/BTS/TRX layout */
union {
struct {
diff --git a/openbsc/include/openbsc/rest_octets.h b/openbsc/include/openbsc/rest_octets.h
new file mode 100644
index 000000000..4e72c0f87
--- /dev/null
+++ b/openbsc/include/openbsc/rest_octets.h
@@ -0,0 +1,122 @@
+#ifndef _REST_OCTETS_H
+#define _REST_OCTETS_H
+
+#include <sys/types.h>
+#include <openbsc/gsm_04_08.h>
+
+/* generate SI1 rest octets */
+int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos);
+
+struct gsm48_si_selection_params {
+ u_int16_t penalty_time:5,
+ temp_offs:3,
+ cell_resel_off:6,
+ cbq:1,
+ present:1;
+};
+
+struct gsm48_si_power_offset {
+ u_int8_t power_offset:2,
+ present:1;
+};
+
+struct gsm48_si3_gprs_ind {
+ u_int8_t si13_position:1,
+ ra_colour:3,
+ present:1;
+};
+
+struct gsm48_lsa_params {
+ u_int32_t prio_thr:3,
+ lsa_offset:3,
+ mcc:12,
+ mnc:12;
+ unsigned int present;
+};
+
+struct gsm48_si_ro_info {
+ struct gsm48_si_selection_params selection_params;
+ struct gsm48_si_power_offset power_offset;
+ u_int8_t si2ter_indicator;
+ u_int8_t early_cm_ctrl;
+ struct {
+ u_int8_t where:3,
+ present:1;
+ } scheduling;
+ struct gsm48_si3_gprs_ind gprs_ind;
+
+ /* SI 4 specific */
+ struct gsm48_lsa_params lsa_params;
+ u_int16_t cell_id;
+ u_int8_t break_ind; /* do we have SI7 + SI8 ? */
+};
+
+
+/* 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);
+
+/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
+int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4);
+
+enum pbcch_carrier_type {
+ PBCCH_BCCH,
+ PBCCH_ARFCN,
+ PBCCH_MAIO
+};
+
+/* TS 03.60 Chapter 6.3.3.1: Network Mode of Operation */
+enum gprs_nmo {
+ GPRS_NMO_I = 0, /* CS pagin on GPRS paging or traffic channel */
+ GPRS_NMO_II = 1, /* all paging on CCCH */
+ GPRS_NMO_III = 2, /* no paging coordination */
+};
+
+struct gprs_cell_options {
+ enum gprs_nmo nmo;
+ /* T3168: wait for packet uplink assignment message */
+ u_int32_t t3168; /* in milliseconds */
+ /* T3192: wait for release of the TBF after reception of the final block */
+ u_int32_t t3192; /* in milliseconds */
+ u_int32_t drx_timer_max;/* in seconds */
+ u_int32_t bs_cv_max;
+};
+
+/* TS 04.60 Table 12.9.2 */
+struct gprs_power_ctrl_pars {
+ u_int8_t alpha;
+ u_int8_t t_avg_w;
+ u_int8_t t_avg_t;
+ u_int8_t pc_meas_chan;
+ u_int8_t n_avg_i;
+};
+
+struct gsm48_si13_info {
+ struct gprs_cell_options cell_opts;
+ struct gprs_power_ctrl_pars pwr_ctrl_pars;
+ u_int8_t bcch_change_mark;
+ u_int8_t si_change_field;
+ u_int8_t pbcch_present;
+
+ union {
+ struct {
+ u_int8_t rac;
+ u_int8_t spgc_ccch_sup;
+ u_int8_t net_ctrl_ord;
+ u_int8_t prio_acc_thr;
+ } no_pbcch;
+ struct {
+ u_int8_t psi1_rep_per;
+ u_int8_t pb;
+ u_int8_t tsc;
+ u_int8_t tn;
+ enum pbcch_carrier_type carrier_type;
+ u_int16_t arfcn;
+ u_int8_t maio;
+ } pbcch;
+ };
+};
+
+/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */
+int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13);
+
+#endif /* _REST_OCTETS_H */
diff --git a/openbsc/include/openbsc/system_information.h b/openbsc/include/openbsc/system_information.h
new file mode 100644
index 000000000..982a9ac63
--- /dev/null
+++ b/openbsc/include/openbsc/system_information.h
@@ -0,0 +1,6 @@
+#ifndef _SYSTEM_INFO_H
+#define _SYSTEM_INFO_H
+
+int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type);
+
+#endif
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;
}