Max has submitted this change and it was merged.

Change subject: Restructure SI2quater generation
......................................................................


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
---
M openbsc/include/openbsc/gsm_data_shared.h
M openbsc/include/openbsc/rest_octets.h
M openbsc/include/openbsc/system_information.h
M openbsc/src/libbsc/bsc_vty.c
M openbsc/src/libbsc/rest_octets.c
M openbsc/src/libbsc/system_information.c
M openbsc/tests/gsm0408/gsm0408_test.c
M openbsc/tests/gsm0408/gsm0408_test.ok
8 files changed, 241 insertions(+), 163 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/openbsc/include/openbsc/gsm_data_shared.h 
b/openbsc/include/openbsc/gsm_data_shared.h
index edc550e..0e5bc91 100644
--- a/openbsc/include/openbsc/gsm_data_shared.h
+++ b/openbsc/include/openbsc/gsm_data_shared.h
@@ -25,6 +25,7 @@
 #endif
 
 #include <openbsc/common_cs.h>
+#include <openbsc/rest_octets.h>
 
 struct osmo_bsc_data;
 
@@ -485,6 +486,7 @@
        struct gsm_bts_trx_ts ts[TRX_NR_TS];
 };
 
+#define GSM_BTS_SI2Q(bts)      (struct gsm48_system_information_type_2quater 
*)((bts)->si_buf[SYSINFO_TYPE_2quater])
 #define GSM_BTS_SI(bts, i)     (void *)((bts)->si_buf[i])
 #define GSM_LCHAN_SI(lchan, i) (void *)((lchan)->si.buf[i])
 
@@ -717,10 +719,13 @@
        /* bitmask of all SI that are present/valid in si_buf */
        uint32_t si_valid;
        /* 3GPP TS 44.018 Table 10.5.2.33b.1 INDEX and COUNT for SI2quater */
-       uint8_t si2q_index;
-       uint8_t si2q_count;
+       uint8_t si2q_index; /* distinguish individual SI2quater messages */
+       uint8_t si2q_count; /* si2q_index for the last (highest indexed) 
individual SI2quater message */
        /* buffers where we put the pre-computed SI */
        sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE];
+       /* offsets used while generating SI2quater */
+       size_t e_offset;
+       size_t u_offset;
 
        /* ip.accesss Unit ID's have Site/BTS/TRX layout */
        union {
diff --git a/openbsc/include/openbsc/rest_octets.h 
b/openbsc/include/openbsc/rest_octets.h
index 73ce57b..7b324d3 100644
--- a/openbsc/include/openbsc/rest_octets.h
+++ b/openbsc/include/openbsc/rest_octets.h
@@ -13,8 +13,7 @@
 
 /* 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, uint8_t index, uint8_t count, const 
struct osmo_earfcn_si2q *e,
-                         const uint16_t *u, const uint16_t *sc, size_t u_len);
+int rest_octets_si2quater(uint8_t *data, struct gsm_bts *bts);
 int rest_octets_si6(uint8_t *data, bool is1800_net);
 
 struct gsm48_si_selection_params {
diff --git a/openbsc/include/openbsc/system_information.h 
b/openbsc/include/openbsc/system_information.h
index b012107..21016b8 100644
--- a/openbsc/include/openbsc/system_information.h
+++ b/openbsc/include/openbsc/system_information.h
@@ -8,13 +8,12 @@
 struct gsm_bts;
 
 int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type type);
-unsigned uarfcn_size(const uint16_t *u, const uint16_t *sc, size_t u_len);
-unsigned earfcn_size(const struct osmo_earfcn_si2q *e);
+size_t si2q_earfcn_count(const struct osmo_earfcn_si2q *e);
 unsigned range1024_p(unsigned n);
 unsigned range512_q(unsigned m);
 int range_encode(enum gsm48_range r, int *arfcns, int arfcns_used, int *w,
                 int f0, uint8_t *chan_list);
-uint8_t si2q_num(const struct gsm_bts *bts);
+uint8_t si2q_num(struct gsm_bts *bts);
 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);
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 2794d85..2c7b6c0 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -2829,11 +2829,11 @@
                e->prio_valid = true;
        }
 
-       if (si2q_num(bts) < 2)
+       if (si2q_num(bts) < 2) /* FIXME: use SI2Q_MAX_NUM */
                return CMD_SUCCESS;
 
-       vty_out(vty, "Warning: not enough space in SI2quater for a given EARFCN 
"
-               "%u%s", arfcn, VTY_NEWLINE);
+       vty_out(vty, "Warning: not enough space in SI2quater (%u/%u used) for a 
given EARFCN %u%s",
+               bts->si2q_count, 2, arfcn, VTY_NEWLINE); /* FIXME: use 
SI2Q_MAX_NUM */
        osmo_earfcn_del(e, arfcn);
 
        return CMD_WARNING;
diff --git a/openbsc/src/libbsc/rest_octets.c b/openbsc/src/libbsc/rest_octets.c
index af660f1..950e570 100644
--- a/openbsc/src/libbsc/rest_octets.c
+++ b/openbsc/src/libbsc/rest_octets.c
@@ -58,30 +58,63 @@
        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)
+/* 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, struct gsm_bts 
*bts, uint8_t budget)
 {
-       unsigned i;
+       const struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list;
+       unsigned i, skip = 0;
+       size_t offset = bts->e_offset;
+       uint8_t rem = budget - 6, earfcn_budget; /* account for mandatory stop 
bit and THRESH_E-UTRAN_high */
+       /* first we have to properly adjust budget requirements */
+       if (e->prio_valid) /* E-UTRAN_PRIORITY: 3GPP TS 45.008*/
+               rem -= 4;
+       else
+               rem--;
+
+       if (e->thresh_lo_valid) /* THRESH_E-UTRAN_low: */
+               rem -= 6;
+       else
+               rem--;
+
+       if (e->qrxlm_valid) /* E-UTRAN_QRXLEVMIN: */
+               rem -= 6;
+       else
+               rem--;
+
+       /* now we can proceed with actually adding EARFCNs within adjusted 
budget limit */
        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 (skip < offset) {
+                               skip++; /* ignore EARFCNs added on previous 
calls */
+                       } else {
+                               earfcn_budget = 17; /* computer budget 
per-EARFCN */
+                               if (OSMO_EARFCN_MEAS_INVALID == e->meas_bw[i])
+                                       earfcn_budget++;
+                               else
+                                       earfcn_budget += 4;
 
-                       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);
+                               if (rem - earfcn_budget < 0) {
+                                       break;
+                               } else {
+                                       bts->e_offset++;
+                                       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);
+
+       /* Note: we don't support different EARFCN arrays each with different 
priority, threshold etc. */
 
        if (e->prio_valid) {
                /* E-UTRAN_PRIORITY: 3GPP TS 45.008*/
@@ -108,8 +141,7 @@
                bitvec_set_bit(bv, 0);
 }
 
-static inline void append_earfcn(struct bitvec *bv,
-                               const struct osmo_earfcn_si2q *e)
+static inline void append_earfcn(struct bitvec *bv, struct gsm_bts *bts, 
uint8_t budget)
 {
        /* Additions in Rel-5: */
        bitvec_set_bit(bv, H);
@@ -158,9 +190,8 @@
        /* 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);
+       /* N. B: 25 bits are set in append_earfcn() - keep it in sync with 
budget adjustment below: */
+       append_eutran_neib_cell(bv, bts, budget - 25);
 
        /* stop bit - end of Repeated E-UTRAN Neighbour Cells sequence: */
        bitvec_set_bit(bv, 0);
@@ -180,22 +211,43 @@
        bitvec_set_bit(bv, L);
 }
 
-/* Append single FDD UARFCN */
-static inline int append_utran_fdd(struct bitvec *bv, uint16_t u, int *sc,
-                                  size_t length)
+static inline int f0_helper(int *sc, size_t length, uint8_t *chan_list)
 {
-       int f0, w[RANGE_ENC_MAX_ARFCNS] = { 0 };
-       uint8_t chan_list[16] = {0};
+       int w[RANGE_ENC_MAX_ARFCNS] = { 0 };
+
+       return range_encode(ARFCN_RANGE_1024, sc, length, w, 0, chan_list);
+}
+
+/* Estimate how many bits it'll take to append single FDD UARFCN */
+static inline int append_utran_fdd_length(uint16_t u, int *sc, size_t sc_len, 
size_t length)
+{
+       uint8_t chan_list[16] = { 0 };
+       int tmp[sc_len], f0;
+
+       memcpy(tmp, sc, sizeof(tmp));
+
+       f0 = f0_helper(tmp, length, chan_list);
+       if (f0 < 0)
+               return f0;
+
+       return 21 + range1024_p(length);
+}
+
+/* Append single FDD UARFCN */
+static inline int append_utran_fdd(struct bitvec *bv, uint16_t u, int *sc, 
size_t length)
+{
+       uint8_t chan_list[16] = { 0 };
+       int f0 = f0_helper(sc, length, chan_list);
+
+       if (f0 < 0)
+               return f0;
+
        /* 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);
@@ -205,15 +257,17 @@
        f0 = bv->cur_bit;
        bitvec_add_range1024(bv, (struct gsm48_range_1024 *)chan_list);
        bv->cur_bit = f0 + range1024_p(length);
-       return 0;
+
+       return 21 + range1024_p(length);
 }
 
 /* Append multiple FDD UARFCNs */
-static inline int append_uarfcns(struct bitvec *bv, const uint16_t *u,
-                                const uint16_t *sc, size_t length)
+static inline int append_uarfcns(struct bitvec *bv, struct gsm_bts *bts, 
uint8_t budget)
 {
-       int i, j, k, rc, st = 0, a[length];
-       uint16_t cu = u[0]; /* caller ensures that length is positive */
+       const uint16_t *u = bts->si_common.data.uarfcn_list, *sc = 
bts->si_common.data.scramble_list;
+       int i, j, k, rc, st = 0, a[bts->si_common.uarfcn_length];
+       uint16_t cu = u[bts->u_offset]; /* caller ensures that length is 
positive */
+       uint8_t rem = budget - 7; /* account for constant bits right away */
 
        /* 3G Neighbour Cell Description */
        bitvec_set_bit(bv, 1);
@@ -227,24 +281,41 @@
        /* No Bandwidth_FDD */
        bitvec_set_bit(bv, 0);
 
-       for (i = 0; i < length; i++) {
+       for (i = bts->u_offset; i < bts->si_common.uarfcn_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)
+                       rc = append_utran_fdd_length(cu, a, 
bts->si_common.uarfcn_length, k);
+                       if (rc < 0) { /* estimate bit length requirements */
                                return rc;
+                       }
+
+                       if (rem - rc < 0) {
+                               break; /* we have ran out of budget in current 
SI2q */
+                       } else {
+                               rem -= append_utran_fdd(bv, cu, a, k);
+                               bts->u_offset++;
+                       }
                        cu = u[i];
                        st = i; /* update start position */
                }
        }
 
-       /* 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;
+       if (rem > 22) { /* add last UARFCN not covered by previous cycle if it 
could possibly fit into budget */
+               for (i = st, k = 0; i < bts->si_common.uarfcn_length; i++)
+                       a[k++] = sc[i];
+
+               rc = append_utran_fdd_length(cu, a, 
bts->si_common.uarfcn_length, k);
+               if (rc < 0) {
+                       return rc;
+               }
+
+               if (rem - rc >= 0) {
+                       rem -= append_utran_fdd(bv, cu, a, k);
+                       bts->u_offset++;
+               }
+       }
 
        /* stop bit - end of Repeated UTRAN FDD Neighbour Cells */
        bitvec_set_bit(bv, 0);
@@ -256,11 +327,9 @@
 }
 
 /* generate SI2quater rest octets: 3GPP TS 44.018 ยง 10.5.2.33b */
-int rest_octets_si2quater(uint8_t *data, uint8_t index, uint8_t count, const 
struct osmo_earfcn_si2q *e,
-                         const uint16_t *u, const uint16_t *sc, size_t u_len)
+int rest_octets_si2quater(uint8_t *data, struct gsm_bts *bts)
 {
        int rc;
-       unsigned sz;
        struct bitvec bv;
        bv.data = data;
        bv.data_len = 20;
@@ -273,11 +342,10 @@
        /* MP_CHANGE_MARK */
        bitvec_set_bit(&bv, 0);
 
-       /* we do not support multiple si2quater messages at the moment: */
        /* SI2quater_INDEX */
-       bitvec_set_uint(&bv, index, 4);
+       bitvec_set_uint(&bv, bts->si2q_index, 4);
        /* SI2quater_COUNT */
-       bitvec_set_uint(&bv, count, 4);
+       bitvec_set_uint(&bv, bts->si2q_count, 4);
 
        /* No Measurement_Parameters Description */
        bitvec_set_bit(&bv, 0);
@@ -294,22 +362,12 @@
        /* No extension (length) */
        bitvec_set_bit(&bv, 0);
 
-       if (u_len) {
-               sz = uarfcn_size(u, sc, u_len);
+       if (bts->si_common.uarfcn_length) {
                /* Even if we do not append EARFCN we still need to set 3 bits 
*/
-               if (sz + bv.cur_bit + 3 > SI2Q_MAX_LEN) {
-                       LOGP(DRR, LOGL_ERROR, "SI2quater: not enough memory to "
-                            "add UARFCNs bits, current %u + required %u + "
-                            "reminder %u > max %u\n", bv.cur_bit, sz, 3,
-                            SI2Q_MAX_LEN);
-                       return -ENOMEM;
-               }
-
-               rc = append_uarfcns(&bv, u, sc, u_len);
+               rc = append_uarfcns(&bv, bts, SI2Q_MAX_LEN - (bv.cur_bit + 3));
                if (rc < 0) {
-                       LOGP(DRR, LOGL_ERROR, "SI2quater: failed to append %zu "
-                            "UARFCNs due to range encoding failure: %s\n",
-                            u_len, strerror(-rc));
+                       LOGP(DRR, LOGL_ERROR, "SI2quater: failed to append %zu 
UARFCNs due to range encoding failure: %s\n",
+                            bts->si_common.uarfcn_length, strerror(-rc));
                        return rc;
                }
        } else { /* No 3G Neighbour Cell Description */
@@ -321,15 +379,14 @@
        /* No GPRS_3G_MEASUREMENT Parameters Descr. */
        bitvec_set_bit(&bv, 0);
 
-       if (e) {
-               sz = earfcn_size(e);
-               if (sz + bv.cur_bit > SI2Q_MAX_LEN) {
-                       LOGP(DRR, LOGL_ERROR, "SI2quater: not enough memory to "
-                            "add EARFCNs bits, current %u + required %u > max "
-                            "%u\n", bv.cur_bit, sz, SI2Q_MAX_LEN);
+       if (&bts->si_common.si2quater_neigh_list) { /* FIXME: use 
si2q_earfcn_count() in if */
+               append_earfcn(&bv, bts, SI2Q_MAX_LEN - bv.cur_bit);
+
+               /* FIXME: remove following check once multiple SI2q are 
properly supported */
+               if ((bts->e_offset != 
si2q_earfcn_count(&bts->si_common.si2quater_neigh_list)) ||
+                   si2q_earfcn_count(&bts->si_common.si2quater_neigh_list) > 5)
                        return -ENOMEM;
-               }
-               append_earfcn(&bv, e);
+
        } else {
                /* No Additions in Rel-5: */
                bitvec_set_bit(&bv, L);
diff --git a/openbsc/src/libbsc/system_information.c 
b/openbsc/src/libbsc/system_information.c
index 37395f0..0496506 100644
--- a/openbsc/src/libbsc/system_information.c
+++ b/openbsc/src/libbsc/system_information.c
@@ -122,19 +122,22 @@
        }
 }
 
-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 @@
        }
 
        /* 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 @@
        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 @@
        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 @@
        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,21 +714,9 @@
        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;
 }
diff --git a/openbsc/tests/gsm0408/gsm0408_test.c 
b/openbsc/tests/gsm0408/gsm0408_test.c
index 81dc177..265e4b2 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.c
+++ b/openbsc/tests/gsm0408/gsm0408_test.c
@@ -84,18 +84,12 @@
     COMPARE(lai48.lac, ==, htons(0x000f));
 }
 
-static inline void add_arfcn_b(struct osmo_earfcn_si2q *e, uint16_t earfcn,
-                              uint8_t bw)
+static inline void gen(struct gsm_bts *bts, const char *s)
 {
-       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)
-{
+       bts->u_offset = 0;
+       bts->e_offset = 0;
+       bts->si2q_index = 0;
+       bts->si2q_count = 0;
        bts->si_valid = 0;
        bts->si_valid |= (1 << SYSINFO_TYPE_2quater);
        /* should be no-op as entire buffer is filled with padding: */
@@ -106,17 +100,32 @@
                printf("generated %s SI2quater: [%d] %s\n",
                       v ? "valid" : "invalid", r, osmo_hexdump(GSM_BTS_SI(bts, 
SYSINFO_TYPE_2quater), r));
        else
-               printf("failed to generate SI2quater: %s\n", strerror(-r));
+               printf("%s() failed to generate SI2quater: %s\n", s, 
strerror(-r));
 }
 
-static inline void _bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn,
-                             uint16_t scramble, bool diversity)
+static inline void add_earfcn_b(struct gsm_bts *bts, uint16_t earfcn, uint8_t 
bw)
 {
-       int r = bts_uarfcn_add(bts, arfcn, scramble, diversity);
+       struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list;
+       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);
+
+       gen(bts, __func__);
+}
+
+static inline void _bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, 
uint16_t scramble, bool diversity)
+{
+       int r;
+
+       bts->u_offset = 0;
+
+       r = bts_uarfcn_add(bts, arfcn, scramble, diversity);
        if (r < 0)
                printf("failed to add UARFCN to SI2quater: %s\n", strerror(-r));
        else
-               gen(bts);
+               gen(bts, __func__);
 }
 
 static inline void test_si2q_segfault(void)
@@ -131,7 +140,7 @@
 
        _bts_uarfcn_add(bts, 10564, 319, 0);
        _bts_uarfcn_add(bts, 10612, 319, 0);
-       gen(bts);
+       gen(bts, __func__);
 }
 
 static inline void test_si2q_mu(void)
@@ -151,7 +160,7 @@
        _bts_uarfcn_add(bts, 10613, 64, 0);
        _bts_uarfcn_add(bts, 10613, 164, 0);
        _bts_uarfcn_add(bts, 10613, 14, 0);
-       gen(bts);
+       gen(bts, __func__);
 }
 
 static inline void test_si2q_u(void)
@@ -165,7 +174,7 @@
        bts = gsm_bts_alloc(network);
 
        /* first generate invalid SI as no UARFCN added */
-       gen(bts);
+       gen(bts, __func__);
        /* subsequent calls should produce valid SI if there's enough memory */
        _bts_uarfcn_add(bts, 1982, 13, 1);
        _bts_uarfcn_add(bts, 1982, 44, 0);
@@ -178,7 +187,7 @@
        _bts_uarfcn_add(bts, 1982, 223, 1);
        _bts_uarfcn_add(bts, 1982, 14, 0);
        _bts_uarfcn_add(bts, 1982, 88, 0);
-       gen(bts);
+       gen(bts, __func__);
 }
 
 static inline void test_si2q_e(void)
@@ -191,40 +200,22 @@
                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.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);
        /* first generate invalid SI as no EARFCN added */
-       gen(bts);
+       gen(bts, __func__);
        /* subsequent calls should produce valid SI if there's enough memory */
-       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);
+       add_earfcn_b(bts, 1917, 1);
+       add_earfcn_b(bts, 1932, OSMO_EARFCN_MEAS_INVALID);
+       add_earfcn_b(bts, 1937, 2);
+       add_earfcn_b(bts, 1945, OSMO_EARFCN_MEAS_INVALID);
+       add_earfcn_b(bts, 1965, OSMO_EARFCN_MEAS_INVALID);
+       add_earfcn_b(bts, 1967, 4);
+       add_earfcn_b(bts, 1982, 3);
 }
 
 static void test_mi_functionality(void)
diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok 
b/openbsc/tests/gsm0408/gsm0408_test.ok
index 1c02dfd..5f9398b 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.ok
+++ b/openbsc/tests/gsm0408/gsm0408_test.ok
@@ -67,16 +67,16 @@
 generated valid SI2quater: [23] 59 06 07 c0 00 25 52 e8 0a 7f 52 88 0a 7e 10 
99 64 00 0b 2b 2b 2b 2b 
 generated valid SI2quater: [23] 59 06 07 c0 00 25 52 e8 0a 7f 52 88 0a 7e 10 
99 64 00 0b 2b 2b 2b 2b 
 Testing SYSINFO_TYPE_2quater EARFCN generation:
-generated invalid SI2quater: [23] 59 06 07 c0 00 04 86 59 0a 03 2b 2b 2b 2b 2b 
2b 2b 2b 2b 2b 2b 2b 2b 
+generated invalid SI2quater: [23] ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae 
ae ae ae ae ae ae ae ae 
 added EARFCN 1917 - generated valid 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 valid 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 valid 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 valid 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 valid 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
+added EARFCN 1967 - add_earfcn_b() failed to generate SI2quater: Cannot 
allocate memory
+added EARFCN 1982 - add_earfcn_b() failed to generate SI2quater: Cannot 
allocate memory
 Testing SYSINFO_TYPE_2quater UARFCN generation:
-generated invalid SI2quater: [23] 59 06 07 c0 00 04 86 59 00 03 2b 2b 2b 2b 2b 
2b 2b 2b 2b 2b 2b 2b 2b 
+generated invalid SI2quater: [23] ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae 
ae ae ae ae ae ae ae ae 
 generated valid SI2quater: [23] 59 06 07 c0 00 25 0f 7c 0c 1a 10 99 64 00 0b 
2b 2b 2b 2b 2b 2b 2b 2b 
 generated valid SI2quater: [23] 59 06 07 c0 00 25 0f 7c 14 1a 1f 00 44 b2 00 
03 2b 2b 2b 2b 2b 2b 2b 
 generated valid SI2quater: [23] 59 06 07 c0 00 25 0f 7c 18 58 12 f0 84 86 59 
00 03 2b 2b 2b 2b 2b 2b 

-- 
To view, visit https://gerrit.osmocom.org/2588
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ib554cf7ffc949a321571e1ae2ada1160e1b35fa6
Gerrit-PatchSet: 5
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: Max <msur...@sysmocom.de>
Gerrit-Reviewer: Harald Welte <lafo...@gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Max <msur...@sysmocom.de>

Reply via email to