jolly has uploaded this change for review.

View Change

ASCI: Add decoding of SYSTEM INFORMATION TYPE 10 $(ASCI)$

This information can be used by the MS to get infos about neighbor
cells with the same voice group/broadcast call.

Related: OS#5782
Change-Id: I81c7929f6d951d8eef7d08624f0b72830370c448
---
M src/host/layer23/include/osmocom/bb/common/sysinfo.h
M src/host/layer23/src/common/sysinfo.c
M src/host/layer23/src/mobile/gsm48_rr.c
3 files changed, 335 insertions(+), 4 deletions(-)

git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/14/34614/1
diff --git a/src/host/layer23/include/osmocom/bb/common/sysinfo.h b/src/host/layer23/include/osmocom/bb/common/sysinfo.h
index 0368901..594d336 100644
--- a/src/host/layer23/include/osmocom/bb/common/sysinfo.h
+++ b/src/host/layer23/include/osmocom/bb/common/sysinfo.h
@@ -18,12 +18,27 @@
#define FREQ_TYPE_REP_5bis 0x40 /* sub channel of SI 5bis */
#define FREQ_TYPE_REP_5ter 0x80 /* sub channel of SI 5ter */

+struct si10_cell_info {
+ uint8_t index; /* frequency index of the frequencies received in SI5* */
+ int16_t arfcn; /* ARFCN or -1 (if not found in SI5*) */
+ uint8_t bsic;
+ bool barred; /* Cell is barred, values below are invalid. */
+ bool la_different; /* Location area is different, so CRH is valid. */
+ uint8_t cell_resel_hyst_db;
+ uint8_t ms_txpwr_max_cch;
+ uint8_t rxlev_acc_min_db;
+ uint8_t cell_resel_offset;
+ uint8_t temp_offset;
+ uint8_t penalty_time;
+};
+
/* structure of all received system information */
struct gsm48_sysinfo {
/* flags of available information */
uint8_t si1, si2, si2bis, si2ter, si3,
si4, si5, si5bis, si5ter, si6,
si13;
+ bool si10;

/* memory maps to simply detect change in system info messages */
uint8_t si1_msg[23];
@@ -36,6 +51,7 @@
uint8_t si5b_msg[18];
uint8_t si5t_msg[18];
uint8_t si6_msg[18];
+ uint8_t si10_msg[21];
uint8_t si13_msg[23];

struct gsm_sysinfo_freq freq[1024]; /* all frequencies */
@@ -158,6 +174,10 @@
uint8_t nb_reest_denied; /* 1 = denied */
uint8_t nb_cell_barr; /* 1 = barred */
uint16_t nb_class_barr; /* bit 10 is emergency */
+
+ /* SI 10 */
+ uint8_t si10_cells; /* number neighbor cells found in SI 10 */
+ struct si10_cell_info si10_cell[32]; /* 32 neighbor cell descriptions */
};

char *gsm_print_arfcn(uint16_t arfcn);
@@ -191,6 +211,8 @@
const struct gsm48_system_information_type_5ter *si, int len);
int gsm48_decode_sysinfo6(struct gsm48_sysinfo *s,
const struct gsm48_system_information_type_6 *si, int len);
+int gsm48_decode_sysinfo10(struct gsm48_sysinfo *s,
+ const struct gsm48_system_information_type_10 *si, int len);
int gsm48_decode_sysinfo13(struct gsm48_sysinfo *s,
const struct gsm48_system_information_type_13 *si, int len);
int gsm48_decode_mobile_alloc(struct gsm_sysinfo_freq *freq,
diff --git a/src/host/layer23/src/common/sysinfo.c b/src/host/layer23/src/common/sysinfo.c
index 12780c2..d2ed792 100644
--- a/src/host/layer23/src/common/sysinfo.c
+++ b/src/host/layer23/src/common/sysinfo.c
@@ -601,6 +601,188 @@
return 0;
}

+/* Decode "SI 10 Rest Octets" (10.5.2.44) */
+static int gsm48_decode_si10_rest_first(struct gsm48_sysinfo *s, struct bitvec *bv,
+ struct si10_cell_info *c)
+{
+ uint8_t ba_ind;
+
+ /* <BA ind : bit(1)> */
+ ba_ind = bitvec_get_uint(bv, 1);
+ if (ba_ind != s->nb_ba_ind_si5) {
+ LOGP(DRR, LOGL_NOTICE, "SI10: Band indicator %u != band indicator %u of SI5!\n", ba_ind,
+ s->nb_ba_ind_si5);
+ return EOF;
+ }
+
+ /* { L <spare padding> | H <neighbour information> } */
+ if (bitvec_get_bit_high(bv) != H) {
+ LOGP(DRR, LOGL_INFO, "SI10: No neighbor cell defined.\n");
+ return EOF;
+ }
+
+ /* <first frequency: bit(5)> */
+ c->index = bitvec_get_uint(bv, 5);
+
+ /* <bsic : bit(6)> */
+ c->bsic = bitvec_get_uint(bv, 6);
+
+ /* { H <cell parameters> | L } */
+ if (bitvec_get_bit_high(bv) != H) {
+ LOGP(DRR, LOGL_NOTICE, "SI10: No cell parameter for first cell, cannot continue to decode!\n");
+ return EOF;
+ }
+
+ /* <cell barred (H)> | L <further cell info> */
+ if (bitvec_get_bit_high(bv) == H) {
+ c->barred = true;
+ return 0;
+ }
+
+ /* { H <cell reselect hysteresis : bit(3)> | L } */
+ if (bitvec_get_bit_high(bv) == H) {
+ c->la_different = true;
+ c->cell_resel_hyst_db = bitvec_get_uint(bv, 3) * 2;
+ }
+
+ /* <ms txpwr max cch : bit(5)> */
+ c->ms_txpwr_max_cch = bitvec_get_uint(bv, 5);
+ /* <rxlev access min : bit(6)> */
+ c->rxlev_acc_min_db = bitvec_get_uint(bv, 6) - 110;
+ /* <cell reselect offset : bit(6)> */
+ c->cell_resel_offset = bitvec_get_uint(bv, 6);
+ /* <temporary offset : bit(3)> */
+ c->temp_offset = bitvec_get_uint(bv, 3);
+ /* <penalty time : bit(5)> */
+ c->penalty_time = bitvec_get_uint(bv, 5);
+
+ return 0;
+}
+
+static int gsm48_decode_si10_rest_other(struct gsm48_sysinfo *s, struct bitvec *bv,
+ struct si10_cell_info *c)
+{
+ int rc;
+
+ /* { H <info field> }** L <spare padding> */
+ if (bitvec_get_bit_high(bv) != H)
+ return EOF;
+
+ c->index = (c->index + 1) & 0x1f;
+ /* <next frequency (H)>** L <differential cell info> */
+ /* Increment frequency number for every <info field> and every <next frequency> occurence. */
+ while ((rc = bitvec_get_bit_high(bv)) == H)
+ c->index = (c->index + 1) & 0x1f;
+ if (rc < 0)
+ goto short_read;
+
+ /* { H <BCC : bit(3)> | L <bsic : bit(6)> } */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc == H) {
+ rc = bitvec_get_uint(bv, 3);
+ if (rc < 0)
+ goto short_read;
+ c->bsic = (c->bsic & 0x07) | rc;
+ } else {
+ rc = bitvec_get_uint(bv, 6);
+ if (rc < 0)
+ goto short_read;
+ c->bsic = rc;
+ }
+
+ /* { H <diff cell pars> | L } */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc != H)
+ return 0;
+
+ /* <cell barred (H)> | L <further cell info> */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc == H) {
+ c->barred = true;
+ return 0;
+ }
+
+ /* { H <cell reselect hysteresis : bit(3)> | L } */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc == H) {
+ c->la_different = true;
+ rc = bitvec_get_uint(bv, 3);
+ if (rc < 0)
+ goto short_read;
+ c->cell_resel_hyst_db = bitvec_get_uint(bv, 3) * 2;
+ }
+
+ /* { H <ms txpwr max cch : bit(5)> | L } */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc == H) {
+ rc = bitvec_get_uint(bv, 5);
+ if (rc < 0)
+ goto short_read;
+ c->ms_txpwr_max_cch = rc;
+ }
+
+ /* { H <rxlev access min : bit(6)> | L } */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc == H) {
+ rc = bitvec_get_uint(bv, 6);
+ if (rc < 0)
+ goto short_read;
+ c->rxlev_acc_min_db = rc - 110;
+ } else
+ c->rxlev_acc_min_db = - 110;
+
+ /* { H <cell reselect offset : bit(6)> | L } */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc == H) {
+ rc = bitvec_get_uint(bv, 6);
+ if (rc < 0)
+ goto short_read;
+ c->cell_resel_offset = rc;
+ }
+
+ /* { H <temporary offset : bit(3)> | L } */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc == H) {
+ rc = bitvec_get_uint(bv, 3);
+ if (rc < 0)
+ goto short_read;
+ c->temp_offset = rc;
+ }
+
+ /* { H <penalty time : bit(5)> | L } */
+ rc = bitvec_get_bit_high(bv);
+ if (rc < 0)
+ goto short_read;
+ if (rc == H) {
+ rc = bitvec_get_uint(bv, 5);
+ if (rc < 0)
+ goto short_read;
+ c->penalty_time = rc;
+ }
+
+ return 0;
+
+short_read:
+ LOGP(DRR, LOGL_NOTICE, "SI10: Short read of differential cell info.\n");
+ return -EINVAL;
+}
+
int gsm48_decode_sysinfo1(struct gsm48_sysinfo *s,
const struct gsm48_system_information_type_1 *si, int len)
{
@@ -787,6 +969,7 @@
0xce, FREQ_TYPE_REP_5);

s->si5 = 1;
+ s->si10 = false;

return 0;
}
@@ -804,6 +987,7 @@
0xce, FREQ_TYPE_REP_5bis);

s->si5bis = 1;
+ s->si10 = false;

return 0;
}
@@ -821,6 +1005,7 @@
0x8e, FREQ_TYPE_REP_5ter);

s->si5ter = 1;
+ s->si10 = false;

return 0;
}
@@ -852,6 +1037,90 @@
return 0;
}

+static int16_t arfcn_from_freq(struct gsm48_sysinfo *s, uint16_t index)
+{
+ uint16_t arfcn, i = 0;
+
+ /* First, search for the P-GSM ARFCN. */
+ for (arfcn = 1; arfcn < 124; arfcn++) {
+ if (!(s->freq[arfcn].mask & FREQ_TYPE_REP))
+ continue;
+ if (index == i++)
+ return arfcn;
+ }
+
+ /* Second, search for ARFCN 0. */
+ if ((s->freq[arfcn].mask & FREQ_TYPE_REP)) {
+ if (index == i++)
+ return arfcn;
+ }
+
+ /* Third, search for all other ARFCN. */
+ for (arfcn = 125; arfcn < 1024; arfcn++) {
+ if (!(s->freq[arfcn].mask & FREQ_TYPE_REP))
+ continue;
+ if (index == i++)
+ return arfcn;
+ }
+
+ /* If not found, return EOF (-1) as idicator. */
+ return EOF;
+}
+
+int gsm48_decode_sysinfo10(struct gsm48_sysinfo *s,
+ const struct gsm48_system_information_type_10 *si, int len)
+{
+ int payload_len = len - sizeof(*si);
+ struct bitvec bv;
+ int i;
+ int rc;
+
+ bv = (struct bitvec) {
+ .data_len = payload_len,
+ .data = (uint8_t *)si->rest_octets,
+ };
+
+ memcpy(s->si10_msg, si, OSMO_MIN(len, sizeof(s->si10_msg)));
+
+ /* Clear cell list. */
+ s->si10_cells = 0;
+ memset(s->si10_cell, 0, sizeof(s->si10_cell));
+
+ /* SI 10 Rest Octets of first neighbor cell, if included. */
+ rc = gsm48_decode_si10_rest_first(s, &bv, &s->si10_cell[0]);
+ puts("1");
+ if (rc == EOF) {
+ puts("2");
+ s->si10 = true;
+ return 0;
+ }
+ puts("3");
+ if (rc < 0)
+ return rc;
+ puts("5");
+ s->si10_cell[0].arfcn = arfcn_from_freq(s, s->si10_cell[0].index);
+ s->si10_cells++;
+
+ for (i = 1; i < ARRAY_SIZE(s->si10_cell); i++) {
+ /* Clone last cell info and then store differential elements. */
+ memcpy(&s->si10_cell[i], &s->si10_cell[i - 1], sizeof(s->si10_cell[i]));
+ /* SI 10 Rest Octets of other neighbor cell, if included. */
+ rc = gsm48_decode_si10_rest_other(s, &bv, &s->si10_cell[i]);
+ if (rc == EOF)
+ break;
+ puts("6");
+ if (rc < 0)
+ return rc;
+ puts("7");
+ s->si10_cell[i].arfcn = arfcn_from_freq(s, s->si10_cell[i].index);
+ s->si10_cells++;
+ }
+ puts("8");
+
+ s->si10 = true;
+ return 0;
+}
+
int gsm48_decode_sysinfo13(struct gsm48_sysinfo *s,
const struct gsm48_system_information_type_13 *si, int len)
{
diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c
index a515338..502d7fe 100644
--- a/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/src/host/layer23/src/mobile/gsm48_rr.c
@@ -2897,13 +2897,40 @@
return gsm48_new_sysinfo(ms, si->system_information);
}

-/* Receive "SYSTEM INFORMATION TYPE 10" message (9.1.50). */
+/* receive "SYSTEM INFORMATION 10" message (9.1.50) */
static int gsm48_rr_rx_sysinfo_10(struct osmocom_ms *ms, struct msgb *msg)
{
- LOGP(DRR, LOGL_INFO, "SYSINFO 10\n");
+ /* NOTE: Short L2 header is included in this structure */
+ struct gsm48_system_information_type_10 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->cellsel.si;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);

- /* Ignore content. */
- return -ENOTSUP;
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 10 "
+ "ignored\n");
+ return -EINVAL;
+ }
+
+ if (payload_len < 20) {
+ LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 10 "
+ "message.\n");
+ return -EINVAL;
+ }
+
+ /* No complete SI5, cannot decode yet. */
+ if (!s->si5 || !(s->si5bis || !s->nb_ext_ind_si5))
+ return 0;
+
+ /* We decode when changed or when SI10 could not decoded, due to missing neighbor cell infos. */
+ if (!memcmp(si, s->si10_msg, OSMO_MIN(msgb_l3len(msg), sizeof(s->si10_msg))) && s->si10)
+ return 0;
+
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 10\n");
+
+ gsm48_decode_sysinfo10(s, si, msgb_l3len(msg));
+
+ /* We cannot call gsm48_new_sysinfo, because it requires regular message types. */
+ return 0;
}

/* receive "SYSTEM INFORMATION 13" message (9.1.43a) */

To view, visit change 34614. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: I81c7929f6d951d8eef7d08624f0b72830370c448
Gerrit-Change-Number: 34614
Gerrit-PatchSet: 1
Gerrit-Owner: jolly <andreas@eversberg.eu>
Gerrit-MessageType: newchange