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.
This commit is contained in:
Harald Welte 2009-12-01 18:04:30 +05:30
parent 4d42bd80bb
commit a54a2bbfc9
13 changed files with 1220 additions and 294 deletions

View File

@ -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 */

View File

@ -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 */

View File

@ -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 {

View File

@ -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 */

View File

@ -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

View File

@ -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 \

View File

@ -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);
}
}

123
openbsc/src/bitvec.c Normal file
View File

@ -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;
}

View File

@ -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;

View File

@ -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);

393
openbsc/src/rest_octets.c Normal file
View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}