diff options
author | Max <msuraev@sysmocom.de> | 2017-05-12 17:00:30 +0200 |
---|---|---|
committer | Max <msuraev@sysmocom.de> | 2017-05-15 13:11:48 +0000 |
commit | f39d03ad21d8120af847603d9b2ead71b8c4ba43 (patch) | |
tree | c684ad88060f40d0df224cbe9aac7897fd936652 /openbsc/src/libbsc/system_information.c | |
parent | 1ebf23b7fe631dbafcc2dc4a1e8a8beced4ecc0d (diff) |
Restructure SI2quater generation
In preparation for extended SI2q messages:
* add SI2q-specific accessor macro
* add *_offset variables to gsm_bts struct
* internalize memory check while generating rest octets - introduce
budget concept (number of bits available in a given message)
* internalize *arfcn_size() functions as they are not needed outside of
si2q_num() anymore
* change rest octets generation to work with gsm_bts struct directly
* do not generate rest octets if no SI2q is necessary
* adjust unit tests accordingly (cosmetic changes only to avoid
regressions)
Requires: I92e12e91605bdab9916a3f665705287572434f74 in libosmocore
Change-Id: Ib554cf7ffc949a321571e1ae2ada1160e1b35fa6
Related: RT#8792
Diffstat (limited to 'openbsc/src/libbsc/system_information.c')
-rw-r--r-- | openbsc/src/libbsc/system_information.c | 89 |
1 files changed, 58 insertions, 31 deletions
diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c index 37395f00f..0496506b6 100644 --- a/openbsc/src/libbsc/system_information.c +++ b/openbsc/src/libbsc/system_information.c @@ -122,19 +122,22 @@ unsigned range512_q(unsigned m) } } -unsigned earfcn_size(const struct osmo_earfcn_si2q *e) +static inline unsigned earfcn_size(const struct gsm_bts *bts) { + const struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; /* EARFCN */ + /* account for all the constant bits in append_earfcn() */ - return 25 + osmo_earfcn_bit_size(e); + return 25 + osmo_earfcn_bit_size_ext(e, bts->e_offset); } -unsigned uarfcn_size(const uint16_t *u, const uint16_t *sc, size_t u_len) +static inline unsigned uarfcn_size(const struct gsm_bts *bts) { - /*account for all the constant bits in append_uarfcns() */ + const uint16_t *u = bts->si_common.data.uarfcn_list; + uint16_t cu = u[bts->u_offset]; /* UARFCN */ + /* account for all the constant bits in append_uarfcns() */ unsigned s = 7, append = 22, r = 0, i, st = 0, j, k; - uint16_t cu = u[0]; - for (i = 0; i < u_len; i++) { + for (i = bts->u_offset; i < bts->si_common.uarfcn_length; i++) { for (j = st, k = 0; j < i; j++, k++); if (u[i] != cu) { /* we've reached new UARFCN */ r += (append + range1024_p(k)); @@ -144,18 +147,25 @@ unsigned uarfcn_size(const uint16_t *u, const uint16_t *sc, size_t u_len) } /* add last UARFCN not covered by previous cycle */ - for (i = st, k = 0; i < u_len; i++, k++); + for (i = st, k = 0; i < bts->si_common.uarfcn_length; i++, k++); return s + r + append + range1024_p(k); } -uint8_t si2q_num(const struct gsm_bts *bts) +uint8_t si2q_num(struct gsm_bts *bts) { - const struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; /* EARFCN */ - const uint16_t *u = bts->si_common.data.uarfcn_list, *sc = bts->si_common.data.scramble_list; /* UARFCN */ - size_t l = bts->si_common.uarfcn_length, e_sz = e ? earfcn_size(e) : 1, u_sz = l ? uarfcn_size(u, sc, l) : 1; + size_t est, e_sz = 1, u_sz = 1; + + if (&bts->si_common.si2quater_neigh_list) /* EARFCN */ + e_sz = earfcn_size(bts); + + if (bts->si_common.uarfcn_length) /* UARFCN */ + u_sz = uarfcn_size(bts); + /* 2 bits are used in between UARFCN and EARFCN structs */ - return 1 + (e_sz + u_sz) / (SI2Q_MAX_LEN - (SI2Q_MIN_LEN + 2)); + est = 1 + (e_sz + u_sz) / (SI2Q_MAX_LEN - (SI2Q_MIN_LEN + 2)); + + return est; } /* 3GPP TS 44.018, Table 9.1.54.1 - prepend diversity bit to scrambling code */ @@ -191,8 +201,7 @@ int bts_uarfcn_del(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble) return 0; } -int bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, - bool diversity) +int bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, bool diversity) { size_t len = bts->si_common.uarfcn_length, i, k = 0; uint16_t scr, chk, @@ -228,7 +237,7 @@ int bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, scl[k] = scr; bts->si_common.uarfcn_length++; - if (si2q_num(bts) < 2) + if (si2q_num(bts) < 2) /* FIXME: use SI2Q_MAX_NUM */ return 0; bts_uarfcn_del(bts, arfcn, scramble); @@ -662,11 +671,41 @@ static int generate_si2ter(enum osmo_sysinfo_type t, struct gsm_bts *bts) return sizeof(*si2t); } +/* SI2quater messages are optional - we only generate them when neighbor UARFCNs or EARFCNs are configured */ +static inline bool si2quater_not_needed(struct gsm_bts *bts) +{ + unsigned i = MAX_EARFCN_LIST; + + if (bts->si_common.si2quater_neigh_list.arfcn) + for (i = 0; i < MAX_EARFCN_LIST; i++) + if (bts->si_common.si2quater_neigh_list.arfcn[i] != OSMO_EARFCN_INVALID) + break; + + if (!bts->si_common.uarfcn_length && i == MAX_EARFCN_LIST) { + bts->si_valid &= ~(1 << SYSINFO_TYPE_2quater); /* mark SI2q as invalid if no (E|U)ARFCNs are present */ + return true; + } + + return false; +} + +size_t si2q_earfcn_count(const struct osmo_earfcn_si2q *e) +{ + unsigned i, ret = 0; + for (i = 0; i < e->length; i++) + if (e->arfcn[i] != OSMO_EARFCN_INVALID) + ret++; + + return ret; +} + static int generate_si2quater(enum osmo_sysinfo_type t, struct gsm_bts *bts) { - int rc, i = MAX_EARFCN_LIST; - struct gsm48_system_information_type_2quater *si2q = - (struct gsm48_system_information_type_2quater *) GSM_BTS_SI(bts, t); + int rc; + struct gsm48_system_information_type_2quater *si2q = GSM_BTS_SI2Q(bts); + + if (si2quater_not_needed(bts)) /* generate rest_octets for SI2q only when necessary */ + return GSM_MACBLOCK_LEN; memset(si2q, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); @@ -675,22 +714,10 @@ static int generate_si2quater(enum osmo_sysinfo_type t, struct gsm_bts *bts) si2q->header.skip_indicator = 0; si2q->header.system_information = GSM48_MT_RR_SYSINFO_2quater; - rc = rest_octets_si2quater(si2q->rest_octets, bts->si2q_index, bts->si2q_count, - &bts->si_common.si2quater_neigh_list, - bts->si_common.data.uarfcn_list, - bts->si_common.data.scramble_list, - bts->si_common.uarfcn_length); + rc = rest_octets_si2quater(si2q->rest_octets, bts); if (rc < 0) return rc; - if (bts->si_common.si2quater_neigh_list.arfcn) - for (i = 0; i < MAX_EARFCN_LIST; i++) - if (bts->si_common.si2quater_neigh_list.arfcn[i] != - OSMO_EARFCN_INVALID) - break; - if (!bts->si_common.uarfcn_length && i == MAX_EARFCN_LIST) - bts->si_valid &= ~(1 << SYSINFO_TYPE_2quater); - return sizeof(*si2q) + rc; } |