Add basic SI2quater support

* support for sending arbitrary static SI2quater.
* vty interface for neightbor EARFCNs specific to SI2quater.
* dynamic generation of SI2quater messages.
* unit test for SI2quater messages.

Fixes: OS#1630
This commit is contained in:
Max 2016-04-15 16:04:46 +02:00 committed by Harald Welte
parent 5fa7e36bbc
commit 59a1bf3dae
10 changed files with 391 additions and 4 deletions

View File

@ -105,6 +105,7 @@ struct gsm_abis_mo {
#define A38_XOR_MAX_KEY_LEN 16
#define A38_COMP128_KEY_LEN 16
#define RSL_ENC_ALG_A5(x) (x+1)
#define MAX_EARFCN_LIST 512
/* is the data link established? who established it? */
#define LCHAN_SAPI_UNUSED 0
@ -715,12 +716,16 @@ struct gsm_bts {
struct bitvec neigh_list;
struct bitvec cell_alloc;
struct bitvec si5_neigh_list;
struct bitvec si2quater_na_list;
struct osmo_earfcn_si2q si2quater_neigh_list;
struct {
/* bitmask large enough for all possible ARFCN's */
uint8_t neigh_list[1024/8];
uint8_t cell_alloc[1024/8];
/* If the user wants a different neighbor list in SI5 than in SI2 */
uint8_t si5_neigh_list[1024/8];
uint8_t meas_bw_list[MAX_EARFCN_LIST];
uint16_t earfcn_list[MAX_EARFCN_LIST];
} data;
} si_common;

View File

@ -1,10 +1,15 @@
#ifndef _REST_OCTETS_H
#define _REST_OCTETS_H
#include <stdbool.h>
#include <openbsc/gsm_04_08.h>
#include <osmocom/gsm/sysinfo.h>
/* generate SI1 rest octets */
int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net);
int rest_octets_si2quater(uint8_t *data,
const struct osmo_earfcn_si2q *e, bool uarfcn,
bool earfcn);
struct gsm48_si_selection_params {
uint16_t penalty_time:5,

View File

@ -192,9 +192,9 @@ int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx)
return 0;
err_out:
LOGP(DRR, LOGL_ERROR, "Cannot generate SI%s for BTS %u, most likely "
"a problem with neighbor cell list generation\n",
get_value_string(osmo_sitype_strs, i), bts->nr);
LOGP(DRR, LOGL_ERROR, "Cannot generate SI%s for BTS %u: error <%s>,"
"most likely a problem with neighbor cell list generation\n",
get_value_string(osmo_sitype_strs, i), bts->nr, strerror(-rc));
return rc;
}

View File

@ -692,6 +692,21 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
}
}
for (i = 0; i < MAX_EARFCN_LIST; i++) {
if (bts->si_common.si2quater_neigh_list.arfcn[i] !=
OSMO_EARFCN_INVALID) {
vty_out(vty, " si2quater neighbor-list add earfcn %u threshold %u",
bts->si_common.si2quater_neigh_list.arfcn[i],
bts->si_common.si2quater_neigh_list.thresh_hi);
if (bts->si_common.si2quater_neigh_list.meas_bw[i] !=
OSMO_EARFCN_MEAS_INVALID)
vty_out(vty, " %u",
bts->si_common.si2quater_neigh_list.meas_bw[i]);
vty_out(vty, "%s", VTY_NEWLINE);
}
}
vty_out(vty, " codec-support fr");
if (bts->codec.hr)
vty_out(vty, " hr");
@ -2743,6 +2758,60 @@ DEFUN(cfg_bts_neigh, cfg_bts_neigh_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_si2quater_neigh_add, cfg_bts_si2quater_neigh_add_cmd,
"si2quater neighbor-list add earfcn <1900-2200> threshold <0-1000> "
"[<0-255>]", "SI2quater Neighbor List\n"
"SI2quater Neighbor List\n" "Add to manual SI2quater neighbor list\n"
"EARFCN of neighbor\n" "EARFCN of neighbor\n" "threshold high bits\n"
"threshold high bits\n" "measurement bandwidth\n")
{
struct gsm_bts *bts = vty->index;
struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list;
uint16_t arfcn = atoi(argv[0]);
uint8_t meas = OSMO_EARFCN_MEAS_INVALID, thresh = atoi(argv[1]);
int r;
if (3 == argc)
meas = atoi(argv[2]);
r = osmo_earfcn_add(e, arfcn, meas);
if (r < 0) {
vty_out(vty, "Unable to add arfcn %u: %s%s", arfcn, strerror(r),
VTY_NEWLINE);
return CMD_WARNING;
}
if (e->thresh_hi && thresh != e->thresh_hi)
vty_out(vty, "Warning: multiple thresholds are not supported, "
"overriding previous threshold %u%s",
e->thresh_hi, VTY_NEWLINE);
e->thresh_hi = thresh;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_si2quater_neigh_del, cfg_bts_si2quater_neigh_del_cmd,
"si2quater neighbor-list del earfcn <1900-2200>",
"SI2quater Neighbor List\n"
"SI2quater Neighbor List\n"
"Delete from SI2quater manual neighbor list\n"
"EARFCN of neighbor\n")
{
struct gsm_bts *bts = vty->index;
struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list;
uint16_t arfcn = atoi(argv[1]);
int r = osmo_earfcn_del(e, arfcn);
if (r < 0) {
vty_out(vty, "Unable to delete arfcn %u: %s%s", arfcn,
strerror(r), VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_bts_si5_neigh, cfg_bts_si5_neigh_cmd,
"si5 neighbor-list (add|del) arfcn <0-1023>",
"SI5 Neighbor List\n"
@ -3873,6 +3942,8 @@ int bsc_vty_init(const struct log_info *cat)
install_element(BTS_NODE, &cfg_bts_neigh_mode_cmd);
install_element(BTS_NODE, &cfg_bts_neigh_cmd);
install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd);
install_element(BTS_NODE, &cfg_bts_si2quater_neigh_add_cmd);
install_element(BTS_NODE, &cfg_bts_si2quater_neigh_del_cmd);
install_element(BTS_NODE, &cfg_bts_excl_rf_lock_cmd);
install_element(BTS_NODE, &cfg_bts_no_excl_rf_lock_cmd);
install_element(BTS_NODE, &cfg_bts_force_comb_si_cmd);

View File

@ -24,10 +24,15 @@
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <osmocom/core/bitvec.h>
#include <openbsc/rest_octets.h>
#include <openbsc/arfcn_range_encode.h>
#define SI2Q_MAX_LEN 160
/* generate SI1 rest octets */
int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net)
@ -53,6 +58,201 @@ int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net)
return bv.data_len;
}
/* Append Repeated E-UTRAN Neighbour Cell to bitvec:
* see 3GPP TS 44.018 Table 10.5.2.33b.1
*/
static inline void append_eutran_neib_cell(struct bitvec *bv,
const struct osmo_earfcn_si2q *e)
{
unsigned i;
for (i = 0; i < e->length; i++) {
if (e->arfcn[i] != OSMO_EARFCN_INVALID) {
bitvec_set_bit(bv, 1); /* EARFCN: */
bitvec_set_uint(bv, e->arfcn[i], 16);
if (OSMO_EARFCN_MEAS_INVALID == e->meas_bw[i])
bitvec_set_bit(bv, 0);
else {
/* Measurement Bandwidth: 9.1.54 */
bitvec_set_bit(bv, 1);
bitvec_set_uint(bv, e->meas_bw[i], 3);
}
}
}
/* stop bit - end of EARFCN + Measurement Bandwidth sequence */
bitvec_set_bit(bv, 0);
if (e->prio_valid) {
/* E-UTRAN_PRIORITY: 3GPP TS 45.008*/
bitvec_set_bit(bv, 1);
bitvec_set_uint(bv, e->prio, 3);
} else
bitvec_set_bit(bv, 0);
/* THRESH_E-UTRAN_high */
bitvec_set_uint(bv, e->thresh_hi, 5);
if (e->thresh_lo_valid) {
/* THRESH_E-UTRAN_low: */
bitvec_set_bit(bv, 1);
bitvec_set_uint(bv, e->thresh_lo, 5);
} else
bitvec_set_bit(bv, 0);
if (e->qrxlm_valid) {
/* E-UTRAN_QRXLEVMIN: */
bitvec_set_bit(bv, 1);
bitvec_set_uint(bv, e->qrxlm, 5);
} else
bitvec_set_bit(bv, 0);
}
static inline int append_earfcn_size(const struct osmo_earfcn_si2q *e)
{
if (!e)
return -EFAULT;
/* account for all the constant bits */
return 25 + osmo_earfcn_bit_size(e);
}
static inline void append_earfcn(struct bitvec *bv,
const struct osmo_earfcn_si2q *e)
{
/* Additions in Rel-5: */
bitvec_set_bit(bv, H);
/* No 3G Additional Measurement Param. Descr. */
bitvec_set_bit(bv, 0);
/* No 3G ADDITIONAL MEASUREMENT Param. Descr. 2 */
bitvec_set_bit(bv, 0);
/* Additions in Rel-6: */
bitvec_set_bit(bv, H);
/* 3G_CCN_ACTIVE */
bitvec_set_bit(bv, 0);
/* Additions in Rel-7: */
bitvec_set_bit(bv, H);
/* No 700_REPORTING_OFFSET */
bitvec_set_bit(bv, 0);
/* No 810_REPORTING_OFFSET */
bitvec_set_bit(bv, 0);
/* Additions in Rel-8: */
bitvec_set_bit(bv, H);
/* Priority and E-UTRAN Parameters Description */
bitvec_set_bit(bv, 1);
/* No Serving Cell Priority Parameters Descr. */
bitvec_set_bit(bv, 0);
/* No 3G Priority Parameters Description */
bitvec_set_bit(bv, 0);
/* E-UTRAN Parameters Description */
bitvec_set_bit(bv, 1);
/* E-UTRAN_CCN_ACTIVE */
bitvec_set_bit(bv, 0);
/* E-UTRAN_Start: 9.1.54 */
bitvec_set_bit(bv, 1);
/* E-UTRAN_Stop: 9.1.54 */
bitvec_set_bit(bv, 1);
/* No E-UTRAN Measurement Parameters Descr. */
bitvec_set_bit(bv, 0);
/* No GPRS E-UTRAN Measurement Param. Descr. */
bitvec_set_bit(bv, 0);
/* Note: each of next 3 "repeated" structures might be repeated any
(0, 1, 2...) times - we only support 1 and 0 */
/* Repeated E-UTRAN Neighbour Cells */
bitvec_set_bit(bv, 1);
/* Note: we don't support different EARFCN arrays each with different
priority, threshold etc. */
append_eutran_neib_cell(bv, e);
/* stop bit - end of Repeated E-UTRAN Neighbour Cells sequence: */
bitvec_set_bit(bv, 0);
/* Note: following 2 repeated structs are not supported ATM */
/* stop bit - end of Repeated E-UTRAN Not Allowed Cells sequence: */
bitvec_set_bit(bv, 0);
/* stop bit - end of Repeated E-UTRAN PCID to TA mapping sequence: */
bitvec_set_bit(bv, 0);
/* Priority and E-UTRAN Parameters Description ends here */
/* No 3G CSG Description */
bitvec_set_bit(bv, 0);
/* No E-UTRAN CSG Description */
bitvec_set_bit(bv, 0);
/* No Additions in Rel-9: */
bitvec_set_bit(bv, L);
}
/* generate SI2quater rest octets: 3GPP TS 44.018 § 10.5.2.33b */
int rest_octets_si2quater(uint8_t *data, const struct osmo_earfcn_si2q *e,
bool uarfcn, bool earfcn)
{
int rc;
struct bitvec bv;
bv.data = data;
bv.data_len = 20;
bitvec_zero(&bv);
/* BA_IND */
bitvec_set_bit(&bv, 1);
/* 3G_BA_IND */
bitvec_set_bit(&bv, 1);
/* MP_CHANGE_MARK */
bitvec_set_bit(&bv, 0);
/* we do not support multiple si2quater messages at the moment: */
/* SI2quater_INDEX */
bitvec_set_uint(&bv, 0, 4);
/* SI2quater_COUNT */
bitvec_set_uint(&bv, 0, 4);
/* No Measurement_Parameters Description */
bitvec_set_bit(&bv, 0);
/* No GPRS_Real Time Difference Description */
bitvec_set_bit(&bv, 0);
/* No GPRS_BSIC Description */
bitvec_set_bit(&bv, 0);
/* No GPRS_REPORT PRIORITY Description */
bitvec_set_bit(&bv, 0);
/* No GPRS_MEASUREMENT_Parameters Description */
bitvec_set_bit(&bv, 0);
/* No NC Measurement Parameters */
bitvec_set_bit(&bv, 0);
/* No extension (length) */
bitvec_set_bit(&bv, 0);
if (uarfcn) {
} else { /* No 3G Neighbour Cell Description */
bitvec_set_bit(&bv, 0);
}
/* No 3G Measurement Parameters Description */
bitvec_set_bit(&bv, 0);
/* No GPRS_3G_MEASUREMENT Parameters Descr. */
bitvec_set_bit(&bv, 0);
if (earfcn) {
rc = append_earfcn_size(e);
if (rc < 0)
return rc;
if (rc + bv.cur_bit > SI2Q_MAX_LEN)
return -ENOMEM;
append_earfcn(&bv, e);
} else {
/* No Additions in Rel-5: */
bitvec_set_bit(&bv, L);
}
bitvec_spare_padding(&bv, (bv.data_len * 8) - 1);
return bv.data_len;
}
/* Append selection parameters to bitvec */
static void append_selection_params(struct bitvec *bv,
const struct gsm48_si_selection_params *sp)

View File

@ -494,6 +494,28 @@ static int generate_si2ter(uint8_t *output, struct gsm_bts *bts)
return sizeof(*si2t);
}
static int generate_si2quater(uint8_t *output, struct gsm_bts *bts)
{
int rc;
struct gsm48_system_information_type_2quater *si2q =
(struct gsm48_system_information_type_2quater *) output;
memset(si2q, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
si2q->header.l2_plen = GSM48_LEN2PLEN(22);
si2q->header.rr_protocol_discriminator = GSM48_PDISC_RR;
si2q->header.skip_indicator = 0;
si2q->header.system_information = GSM48_MT_RR_SYSINFO_2quater;
rc = rest_octets_si2quater(si2q->rest_octets,
&bts->si_common.si2quater_neigh_list, false,
true);
if (rc < 0)
return rc;
return sizeof(*si2q) + rc;
}
static struct gsm48_si_ro_info si_info = {
.selection_params = {
.present = 0,
@ -831,6 +853,7 @@ static const gen_si_fn_t gen_si_fn[_MAX_SYSINFO_TYPE] = {
[SYSINFO_TYPE_2] = &generate_si2,
[SYSINFO_TYPE_2bis] = &generate_si2bis,
[SYSINFO_TYPE_2ter] = &generate_si2ter,
[SYSINFO_TYPE_2quater] = &generate_si2quater,
[SYSINFO_TYPE_3] = &generate_si3,
[SYSINFO_TYPE_4] = &generate_si4,
[SYSINFO_TYPE_5] = &generate_si5,

View File

@ -315,6 +315,11 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ
bts->neigh_list_manual_mode = 0;
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.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list;
bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list;
bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST;
bts->si_common.si2quater_neigh_list.thresh_hi = 0;
osmo_earfcn_init(&bts->si_common.si2quater_neigh_list);
bts->si_common.neigh_list.data = bts->si_common.data.neigh_list;
bts->si_common.neigh_list.data_len =
sizeof(bts->si_common.data.neigh_list);

View File

@ -7,6 +7,7 @@ EXTRA_DIST = gsm0408_test.ok
gsm0408_test_SOURCES = gsm0408_test.c
gsm0408_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -ldbi
$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS) -ldbi

View File

@ -29,7 +29,11 @@
#include <openbsc/gsm_subscriber.h>
#include <openbsc/debug.h>
#include <openbsc/arfcn_range_encode.h>
#include <openbsc/system_information.h>
#include <openbsc/abis_rsl.h>
#include <osmocom/core/application.h>
#include <osmocom/gsm/sysinfo.h>
#define COMPARE(result, op, value) \
if (!((result) op (value))) {\
@ -79,6 +83,70 @@ static void test_location_area_identifier(void)
COMPARE(lai48.lac, ==, htons(0x000f));
}
static inline void add_arfcn_b(struct osmo_earfcn_si2q *e, uint16_t earfcn,
uint8_t bw)
{
int r = osmo_earfcn_add(e, earfcn, bw);
if (r)
printf("failed to add EARFCN %u: %s\n", earfcn, strerror(r));
else
printf("added EARFCN %u - ", earfcn);
}
static inline void gen(struct gsm_bts *bts)
{
int r = gsm_generate_si(bts, SYSINFO_TYPE_2quater);
if (r > 0)
printf("generated SI2quater: [%d] %s\n", r,
osmo_hexdump(bts->si_buf[SYSINFO_TYPE_2quater], r));
else
printf("failed to generate SI2quater: %s\n", strerror(-r));
}
static inline void test_si2q(void)
{
struct gsm_bts *bts;
struct gsm_network *network = gsm_network_init(1, 1, NULL);
printf("Testing SYSINFO_TYPE_2quater generation:\n");
if (!network)
exit(1);
bts = gsm_bts_alloc(network);
bts->si_common.si2quater_neigh_list.arfcn =
bts->si_common.data.earfcn_list;
bts->si_common.si2quater_neigh_list.meas_bw =
bts->si_common.data.meas_bw_list;
bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST;
bts->si_common.si2quater_neigh_list.thresh_hi = 5;
osmo_earfcn_init(&bts->si_common.si2quater_neigh_list);
add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1917, 1);
gen(bts);
add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1932,
OSMO_EARFCN_MEAS_INVALID);
gen(bts);
add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1937, 2);
gen(bts);
add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1945,
OSMO_EARFCN_MEAS_INVALID);
gen(bts);
add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1965,
OSMO_EARFCN_MEAS_INVALID);
gen(bts);
add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1967, 4);
gen(bts);
add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1982, 3);
gen(bts);
}
static void test_mi_functionality(void)
{
const char *imsi_odd = "987654321098763";
@ -486,6 +554,7 @@ int main(int argc, char **argv)
test_range_encoding();
test_gsm411_rp_ref_wrap();
test_si2q();
printf("Done.\n");
return EXIT_SUCCESS;
}

View File

@ -62,4 +62,12 @@ testing RP-Reference wrap
Allocated reference: 255
Allocated reference: 0
Allocated reference: 1
Testing SYSINFO_TYPE_2quater generation:
added EARFCN 1917 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be c8 50 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
added EARFCN 1932 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 30 14 03 2b 2b 2b 2b 2b 2b 2b 2b
added EARFCN 1937 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a0 a0 2b 2b 2b 2b 2b 2b
added EARFCN 1945 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a8 3c c8 28 0b 2b 2b 2b
added EARFCN 1965 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a8 3c ca 0f 5a 0a 03 2b
added EARFCN 1967 - failed to generate SI2quater: Cannot allocate memory
added EARFCN 1982 - failed to generate SI2quater: Cannot allocate memory
Done.