From e610e700da088ba1c4e5f0478317040f236aaebb Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 19 Dec 2016 13:41:48 +0100 Subject: SI2q: add support for multiple UARFCNs Support multiple UARFCNs with the same Scrambler Code. Fixes: RT#7379 Change-Id: If1c32e8b547a28325180faaaddd21f80c37f7337 --- openbsc/src/libbsc/rest_octets.c | 79 +++++++++++++++++++++------------ openbsc/src/libbsc/system_information.c | 28 ++++++++++-- 2 files changed, 75 insertions(+), 32 deletions(-) (limited to 'openbsc/src/libbsc') diff --git a/openbsc/src/libbsc/rest_octets.c b/openbsc/src/libbsc/rest_octets.c index fc0282e06..6fae9cd87 100644 --- a/openbsc/src/libbsc/rest_octets.c +++ b/openbsc/src/libbsc/rest_octets.c @@ -180,11 +180,40 @@ static inline void append_earfcn(struct bitvec *bv, bitvec_set_bit(bv, L); } -static inline int append_uarfcn(struct bitvec *bv, const uint16_t *u, - const uint16_t *sc, size_t length) +/* Append single FDD UARFCN */ +static inline int append_utran_fdd(struct bitvec *bv, uint16_t u, int *sc, + size_t length) { - int f0_inc, i, w[RANGE_ENC_MAX_ARFCNS] = { 0 }, a[length]; + int f0, w[RANGE_ENC_MAX_ARFCNS] = { 0 }; uint8_t chan_list[16] = {0}; + /* Repeated UTRAN FDD Neighbour Cells */ + bitvec_set_bit(bv, 1); + + /* FDD-ARFCN */ + bitvec_set_bit(bv, 0); + bitvec_set_uint(bv, u, 14); + + f0 = range_encode(ARFCN_RANGE_1024, sc, length, w, 0, chan_list); + if (f0 < 0) + return f0; + + /* FDD_Indic0: parameter value '0000000000' is a member of the set? */ + bitvec_set_bit(bv, f0); + /* NR_OF_FDD_CELLS */ + bitvec_set_uint(bv, length, 5); + + f0 = bv->cur_bit; + bitvec_add_range1024(bv, (struct gsm48_range_1024 *)chan_list); + bv->cur_bit = f0 + range1024_p(length); + return 0; +} + +/* Append multiple FDD UARFCNs */ +static inline int append_uarfcns(struct bitvec *bv, const uint16_t *u, + const uint16_t *sc, size_t length) +{ + int i, j, k, rc, st = 0, a[length]; + uint16_t cu = u[0]; /* caller ensures that length is positive */ /* 3G Neighbour Cell Description */ bitvec_set_bit(bv, 1); @@ -198,31 +227,24 @@ static inline int append_uarfcn(struct bitvec *bv, const uint16_t *u, /* No Bandwidth_FDD */ bitvec_set_bit(bv, 0); - memset(w, 0, sizeof(w)); - for (i = 0; i < length; i++) - a[i] = sc[i]; - - /* Note: we do not support repeating Neighbour Cells ATM */ - /* Repeated UTRAN FDD Neighbour Cells */ - bitvec_set_bit(bv, 1); - - /* FDD-ARFCN */ - bitvec_set_bit(bv, 0); - /* Note: we do not support multiple UARFCN values ATM: */ - bitvec_set_uint(bv, u[0], 14); - - f0_inc = range_encode(ARFCN_RANGE_1024, a, length, w, 0, chan_list); - if (f0_inc < 0) - return f0_inc; - - /* FDD_Indic0: parameter value '0000000000' is not a member of the set */ - bitvec_set_bit(bv, f0_inc); - /* NR_OF_FDD_CELLS */ - bitvec_set_uint(bv, length, 5); + for (i = 0; i < length; i++) { + for (j = st, k = 0; j < i; j++) + a[k++] = sc[j]; /* copy corresponding SCs */ + if (u[i] != cu) { /* we've reached new UARFCN */ + rc = append_utran_fdd(bv, cu, a, k); + if (rc < 0) + return rc; + cu = u[i]; + st = i; /* update start position */ + } + } - i = bv->cur_bit; - bitvec_add_range1024(bv, (struct gsm48_range_1024 *)chan_list); - bv->cur_bit = i + range1024_p(length); + /* add last UARFCN not covered by previous cycle */ + for (i = st, k = 0; i < length; i++) + a[k++] = sc[i]; + rc = append_utran_fdd(bv, cu, a, k); + if (rc < 0) + return rc; /* stop bit - end of Repeated UTRAN FDD Neighbour Cells */ bitvec_set_bit(bv, 0); @@ -282,7 +304,8 @@ int rest_octets_si2quater(uint8_t *data, const struct osmo_earfcn_si2q *e, SI2Q_MAX_LEN); return -ENOMEM; } - rc = append_uarfcn(&bv, u, sc, u_len); + + rc = append_uarfcns(&bv, u, sc, u_len); if (rc < 0) { LOGP(DRR, LOGL_ERROR, "SI2quater: failed to append %zu " "UARFCNs due to range encoding failure: %s\n", diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c index 20c3915e2..e71490eb7 100644 --- a/openbsc/src/libbsc/system_information.c +++ b/openbsc/src/libbsc/system_information.c @@ -130,8 +130,23 @@ unsigned earfcn_size(const struct osmo_earfcn_si2q *e) unsigned uarfcn_size(const uint16_t *u, const uint16_t *sc, size_t u_len) { - /*account for all the constant bits in append_uarfcn() */ - return 29 + range1024_p(u_len); + /*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 (j = st, k = 0; j < i; j++, k++); + if (u[i] != cu) { /* we've reached new UARFCN */ + r += (append + range1024_p(k)); + cu = u[i]; + st = i; /* update start position */ + } + } + + /* add last UARFCN not covered by previous cycle */ + for (i = st, k = 0; i < u_len; i++, k++); + + return s + r + append + range1024_p(k); } bool si2q_size_check(const struct gsm_bts *bts) @@ -184,7 +199,7 @@ int bts_uarfcn_del(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble) 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; + size_t len = bts->si_common.uarfcn_length, i, k = 0; uint16_t scr, chk, *ual = bts->si_common.data.uarfcn_list, *scl = bts->si_common.data.scramble_list, @@ -197,7 +212,11 @@ int bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, if (len == MAX_EARFCN_LIST) return -ENOMEM; - for (i = 0, k = 0; i < len; i++) { + for (i = 0; i < len; i++) /* find the position of arfcn if any */ + if (arfcn == ual[i]) + break; + + for (k = 0; i < len; i++) { if (arfcn == ual[i] && (scr == scl[i] || chk == scl[i])) return -EADDRINUSE; if (scr > scl[i]) @@ -209,6 +228,7 @@ int bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, memmove(ual + k + 1, ual + k, (len - k) * 2); memmove(scl + k + 1, scl + k, (len - k) * 2); } + ual[k] = arfcn; scl[k] = scr; bts->si_common.uarfcn_length++; -- cgit v1.2.3