jolly has submitted this change. (
https://gerrit.osmocom.org/c/osmo-bsc/+/34626?usp=email
)
Change subject: ASCI: Add System Information 10 support
......................................................................
ASCI: Add System Information 10 support
For each BTS, an SI 10 is generated with the informations about all
neighbor BTS that have the same group/broadcast call.
The SI 10 will only define neighbor cells within the same BSC, because
it does not know about neighbor cells within other BSCs.
When multiple channels are used for a group/broadcast call, the SI 10
is generated after all channels have been activated. Subsequent channel
activations result in an update of SI 10 on all channels.
Change-Id: Icd3101e6dd935a57f003253aaef400c2cf95a0c3
---
M include/osmocom/bsc/system_information.h
M src/osmo-bsc/system_information.c
M src/osmo-bsc/vgcs_fsm.c
3 files changed, 331 insertions(+), 2 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
fixeria: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/include/osmocom/bsc/system_information.h
b/include/osmocom/bsc/system_information.h
index f74ef6d..46213f6 100644
--- a/include/osmocom/bsc/system_information.h
+++ b/include/osmocom/bsc/system_information.h
@@ -5,12 +5,17 @@
#include <osmocom/gsm/gsm48_arfcn_range_encode.h>
+/* Complete length of SYSTEM INFORMATION 10 (SACCH) */
+#define SI10_LENGTH 21
+
struct gsm_bts;
int band_compatible(const struct gsm_bts *bts, int arfcn);
int generate_cell_chan_alloc(struct gsm_bts *bts);
int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts);
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type type);
+int gsm_generate_si10(struct gsm48_system_information_type_10 *si10, size_t len,
+ const struct gsm_subscriber_connection *conn);
size_t si2q_earfcn_count(const struct osmo_earfcn_si2q *e);
unsigned range1024_p(unsigned n);
unsigned range512_q(unsigned m);
diff --git a/src/osmo-bsc/system_information.c b/src/osmo-bsc/system_information.c
index 94205aa..477e9fa 100644
--- a/src/osmo-bsc/system_information.c
+++ b/src/osmo-bsc/system_information.c
@@ -1246,6 +1246,269 @@
return l2_plen + rc;
}
+static int si10_rest_octets_encode(struct gsm_bts *s_bts, struct bitvec *bv, struct
gsm_bts *n_bts, uint8_t index)
+{
+ /* The BA-IND must be equal to the BA-IND in SI5*. */
+ /* <BA ind : bit(1)> */
+ bitvec_set_bit(bv, 1);
+
+ /* Do we have neighbor cells ? */
+ /* { L <spare padding> | H <neighbour information> } */
+ if (!n_bts)
+ return 0;
+ bitvec_set_bit(bv, H);
+
+ /* <first frequency: bit(5)> */
+ bitvec_set_uint(bv, index, 5);
+
+ /* <bsic : bit(6)> */
+ bitvec_set_uint(bv, n_bts->bsic, 6);
+
+ /* We do not provide empty cell information. */
+ /* { H <cell parameters> | L } */
+ bitvec_set_bit(bv, H);
+
+ /* If cell is barred, we do not need further cell info. */
+ /* <cell barred> | L <further cell info> */
+ if (n_bts->si_common.rach_control.cell_bar) {
+ /* H */
+ bitvec_set_bit(bv, H);
+ /* We are done with the first cell info. */
+ return 0;
+ }
+ bitvec_set_bit(bv, L);
+
+ /* If LA is different for serving cell, we need to add CRH. */
+ /* { H <cell reselect hysteresis : bit(3)> | L } */
+ if (s_bts->location_area_code != n_bts->location_area_code) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, n_bts->si_common.cell_sel_par.cell_resel_hyst, 3);
+ } else
+ bitvec_set_bit(bv, L);
+
+ /* <ms txpwr max cch : bit(5)> */
+ bitvec_set_uint(bv, n_bts->si_common.cell_sel_par.ms_txpwr_max_ccch, 5);
+
+ /* <rxlev access min : bit(6)> */
+ bitvec_set_uint(bv, n_bts->si_common.cell_sel_par.rxlev_acc_min, 6);
+
+ /* <cell reselect offset : bit(6)> */
+ if (n_bts->si_common.cell_ro_sel_par.present)
+ bitvec_set_uint(bv, n_bts->si_common.cell_ro_sel_par.cell_resel_off, 6);
+ else
+ bitvec_set_uint(bv, 0, 6);
+
+ /* <temporary offset : bit(3)> */
+ if (n_bts->si_common.cell_ro_sel_par.present)
+ bitvec_set_uint(bv, n_bts->si_common.cell_ro_sel_par.temp_offs, 3);
+ else
+ bitvec_set_uint(bv, 0, 3);
+
+ /* <penalty time : bit(5)> */
+ if (n_bts->si_common.cell_ro_sel_par.present)
+ bitvec_set_uint(bv, n_bts->si_common.cell_ro_sel_par.penalty_time, 5);
+ else
+ bitvec_set_uint(bv, 0, 5);
+
+ /* We are done with the first cell info. */
+ return 0;
+}
+
+static int si10_rest_octets_encode_other(struct gsm_bts *s_bts, struct bitvec *bv, struct
gsm_bts *l_bts,
+ struct gsm_bts *n_bts, uint8_t last_index, uint8_t index)
+{
+ int rc;
+
+ /* If the bv buffer would overflow, then the bits are not written. Each bitvec_set_*
call will return
+ * an error code. This error is returned with this function. */
+
+ /* { H <info field> } */
+ bitvec_set_bit(bv, H);
+
+ /* How many frequency indices do we skip? */
+ /* <next frequency>** L <differential cell info> */
+ while ((last_index = (last_index + 1) & 0x1f) != index) {
+ /* H */
+ bitvec_set_bit(bv, H);
+ }
+ bitvec_set_bit(bv, L);
+
+ /* If NCC is equal, just send BCC, otherwise send complete BSIC. */
+ /* { H <BCC : bit(3)> | L <bsic : bit(6)> } */
+ if ((l_bts->bsic & 0x38) == (n_bts->bsic & 0x38))
+ bitvec_set_uint(bv, n_bts->bsic & 0x07, 3);
+ else
+ bitvec_set_uint(bv, n_bts->bsic, 6);
+
+ /* We do not provide empty cell information. */
+ /* { H <cell parameters> | L } */
+ bitvec_set_bit(bv, H);
+
+ /* If cell is barred, we do not need further cell info. */
+ /* <cell barred> | L <further cell info> */
+ if (n_bts->si_common.rach_control.cell_bar) {
+ /* H */
+ rc = bitvec_set_bit(bv, H);
+ /* We are done with the other cell info. */
+ return rc;
+ }
+ bitvec_set_bit(bv, L);
+
+ /* If LA is different for serving cell, we need to add CRH. */
+ /* { H <cell reselect hysteresis : bit(3)> | L } */
+ if (s_bts->location_area_code != n_bts->location_area_code) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, n_bts->si_common.cell_sel_par.cell_resel_hyst, 3);
+ } else
+ bitvec_set_bit(bv, L);
+
+ /* { H <ms txpwr max cch : bit(5)> | L } */
+ if (l_bts->si_common.cell_sel_par.ms_txpwr_max_ccch !=
n_bts->si_common.cell_sel_par.ms_txpwr_max_ccch) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, n_bts->si_common.cell_sel_par.ms_txpwr_max_ccch, 5);
+ } else
+ bitvec_set_bit(bv, L);
+
+ /* { H <rxlev access min : bit(6)> | L } */
+ if (l_bts->si_common.cell_sel_par.rxlev_acc_min !=
n_bts->si_common.cell_sel_par.rxlev_acc_min) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, n_bts->si_common.cell_sel_par.rxlev_acc_min, 6);
+ } else
+ bitvec_set_bit(bv, L);
+
+ /* { H <cell reselect offset : bit(6)> | L } */
+ if (l_bts->si_common.cell_ro_sel_par.present !=
n_bts->si_common.cell_ro_sel_par.present ||
+ (n_bts->si_common.cell_ro_sel_par.present &&
+ l_bts->si_common.cell_ro_sel_par.cell_resel_off !=
n_bts->si_common.cell_ro_sel_par.cell_resel_off)) {
+ bitvec_set_bit(bv, H);
+ if (n_bts->si_common.cell_ro_sel_par.present)
+ bitvec_set_uint(bv, n_bts->si_common.cell_ro_sel_par.cell_resel_off, 6);
+ else
+ bitvec_set_uint(bv, 0, 6);
+ } else
+ bitvec_set_bit(bv, L);
+
+ /* { H <temporary offset : bit(3)> | L } */
+ if (l_bts->si_common.cell_ro_sel_par.present !=
n_bts->si_common.cell_ro_sel_par.present ||
+ (n_bts->si_common.cell_ro_sel_par.present &&
+ l_bts->si_common.cell_ro_sel_par.temp_offs !=
n_bts->si_common.cell_ro_sel_par.temp_offs)) {
+ bitvec_set_bit(bv, H);
+ if (n_bts->si_common.cell_ro_sel_par.present)
+ bitvec_set_uint(bv, n_bts->si_common.cell_ro_sel_par.temp_offs, 3);
+ else
+ bitvec_set_uint(bv, 0, 3);
+ } else
+ bitvec_set_bit(bv, L);
+
+ /* { H <penalty time : bit(5)> | L } */
+ if (l_bts->si_common.cell_ro_sel_par.present !=
n_bts->si_common.cell_ro_sel_par.present ||
+ (n_bts->si_common.cell_ro_sel_par.present &&
+ l_bts->si_common.cell_ro_sel_par.penalty_time !=
n_bts->si_common.cell_ro_sel_par.penalty_time)) {
+ bitvec_set_bit(bv, H);
+ if (n_bts->si_common.cell_ro_sel_par.present)
+ rc = bitvec_set_uint(bv, n_bts->si_common.cell_ro_sel_par.penalty_time, 5);
+ else
+ rc = bitvec_set_uint(bv, 0, 5);
+ } else
+ rc = bitvec_set_bit(bv, L);
+
+ /* We are done with the other cell info. */
+ return rc;
+}
+
+/* Generate SI 10 and return the number of bits used in the rest octet. */
+int gsm_generate_si10(struct gsm48_system_information_type_10 *si10, size_t len,
+ const struct gsm_subscriber_connection *conn)
+{
+ struct bitvec *nbv;
+ struct gsm_bts *s_bts = conn->lchan->ts->trx->bts;
+ int i;
+ bool any_neighbor = false;
+ int rc;
+
+ struct bitvec bv = {
+ .data_len = len - sizeof(*si10),
+ .data = si10->rest_octets,
+ };
+
+ si10->rr_short_pd = 0; /* 3GPP TS 24.007 §11.3.2.1 */
+ si10->msg_type = GSM48_MT_RR_SH_SI10;
+ si10->l2_header = 0; /* 3GPP TS 44.006 §6.4a */
+
+ /* If we have gernerated SI5 with separate SI5 list, the used frequency indexes refer to
it. */
+ if (s_bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP)
+ nbv = &s_bts->si_common.si5_neigh_list;
+ else
+ nbv = &s_bts->si_common.neigh_list;
+
+ /* Get up to 32 possible neighbor frequencies that SI10 can refer to. */
+ for (i = 0; i < 32; i++) {
+ struct gsm_bts *c_bts, *n_bts, *l_bts;
+ struct gsm_subscriber_connection *c;
+ unsigned int save_cur_bit;
+ int16_t arfcn;
+ int last_i;
+ arfcn = neigh_list_get_arfcn(s_bts, nbv, i);
+ /* End of list */
+ if (arfcn < 0)
+ break;
+ /* Is this neighbour used for this group call? */
+ n_bts = NULL;
+ llist_for_each_entry(c, &conn->vgcs_chan.call->vgcs_call.chan_list,
vgcs_chan.list) {
+ if (c == conn)
+ continue;
+ if (!c->lchan)
+ continue;
+ c_bts = c->lchan->ts->trx->bts;
+ if (c_bts->c0->arfcn != arfcn)
+ continue;
+ n_bts = c_bts;
+ break;
+ }
+ if (n_bts) {
+ if (!any_neighbor) {
+ /* First neighbor, so generate rest octets with first cell info. */
+ LOGP(DRR, LOGL_INFO, "SI 10 with cell ID %d.\n", n_bts->cell_identity);
+ rc = si10_rest_octets_encode(s_bts, &bv, n_bts, i);
+ if (rc < 0)
+ return rc;
+ any_neighbor = true;
+ } else {
+ /* Save current position, so we can restore to last position in case of failure. */
+ save_cur_bit = bv.cur_bit;
+ /* Nth neighbor, so add rest octets with differential cell info. */
+ LOGP(DRR, LOGL_INFO, "Append cell ID %d to SI 10.\n",
n_bts->cell_identity);
+ rc = si10_rest_octets_encode_other(s_bts, &bv, l_bts, n_bts, last_i, i);
+ if (rc < 0) {
+ LOGP(DRR, LOGL_INFO, "Skip cell ID %d, SI 10 would overflow.\n",
+ n_bts->cell_identity);
+ /* Resore last position. */
+ bv.cur_bit = save_cur_bit;
+ break;
+ }
+ }
+ last_i = i;
+ l_bts = n_bts;
+ }
+ }
+
+ /* If no neighbor exists, generate rest octets without any neighbor info. */
+ if (!any_neighbor) {
+ LOGP(DRR, LOGL_INFO, "SI 10 without any neighbor cell.\n");
+ rc = si10_rest_octets_encode(s_bts, &bv, NULL, 0);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* Do spare padding. We cannot do it earlier, because encoding might corrupt it if
differential cell info
+ * does not fit into the message. */
+ while ((bv.cur_bit & 7))
+ bitvec_set_bit(&bv, L);
+ memset(bv.data + bv.cur_bit / 8, GSM_MACBLOCK_PADDING, bv.data_len - bv.cur_bit / 8);
+
+ return len;
+}
+
static int generate_si13(enum osmo_sysinfo_type t, struct gsm_bts *bts)
{
struct gsm48_system_information_type_13 *si13 =
diff --git a/src/osmo-bsc/vgcs_fsm.c b/src/osmo-bsc/vgcs_fsm.c
index 8969d4f..22f955a 100644
--- a/src/osmo-bsc/vgcs_fsm.c
+++ b/src/osmo-bsc/vgcs_fsm.c
@@ -53,6 +53,7 @@
#include <osmocom/bsc/gsm_04_08_rr.h>
#include <osmocom/bsc/bts_trx.h>
#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/system_information.h>
#define S(x) (1 << (x))
@@ -129,6 +130,38 @@
* VGCS call FSM
*/
+/* Add/update SI10. It must be called whenever a channel is activated or failed. */
+static void si10_update(struct gsm_subscriber_connection *conn)
+{
+ struct gsm_subscriber_connection *c;
+ uint8_t si10[SI10_LENGTH];
+ int rc;
+
+ /* Skip SI10 update, if not all channels have been activated or failed. */
+ llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list) {
+ if (c->vgcs_chan.fi->state == VGCS_CHAN_ST_WAIT_EST) {
+ LOG_CALL(conn, LOGL_DEBUG, "There is a channel, not yet active. No SI10 update
now.\n");
+ return;
+ }
+ }
+
+ LOG_CALL(conn, LOGL_DEBUG, "New channel(s) added, updating SI10 for all
channels.\n");
+
+ /* Go through all channels. */
+ llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list) {
+ /* Skip all channels that failed to activate or have not been aktivated yet.
+ * There shouldn't be any channel in that state now. */
+ if (!c->lchan)
+ continue;
+ /* Encode SI 10 for this channel. Skip, if it fails. */
+ rc = gsm_generate_si10((struct gsm48_system_information_type_10 *)si10, sizeof(si10),
c);
+ if (rc < 0)
+ continue;
+ /* Add SI 10 to SACCH of this channel c. */
+ rsl_sacch_info_modify(c->lchan, RSL_SYSTEM_INFO_10, si10, sizeof(si10));
+ }
+}
+
static void vgcs_call_detach_and_destroy(struct osmo_fsm_inst *fi, enum
osmo_fsm_term_cause cause)
{
struct gsm_subscriber_connection *conn = fi->priv, *c;
@@ -667,6 +700,9 @@
LOG_CHAN(conn, LOGL_DEBUG, "lchan failed.\n");
/* BTS reports failure on channel request. */
osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_NULL, 0, 0);
+ /* Add/update SI10. */
+ if (conn->vgcs_chan.call)
+ si10_update(conn->vgcs_chan.call);
/* Report failure to MSC. */
bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
break;
@@ -691,9 +727,12 @@
osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_FREE, 0, 0);
else
osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_BLOCKED, 0, 0);
- /* Add call to notification channel. */
- if (conn->vgcs_chan.call)
+ if (conn->vgcs_chan.call) {
+ /* Add call to notification channel. */
rsl_notification_cmd(conn->lchan->ts->trx->bts, conn->lchan,
&conn->vgcs_chan.gc_ie, NULL);
+ /* Add/update SI10. */
+ si10_update(conn->vgcs_chan.call);
+ }
/* Report result to MSC. */
bsc_tx_vgcs_vbs_assignment_result(conn, &conn->vgcs_chan.ct,
&conn->vgcs_chan.ci,
conn->vgcs_chan.call_id);
@@ -702,6 +741,9 @@
LOG_CHAN(conn, LOGL_DEBUG, "MGW endpoint failed.\n");
/* MGW reports failure. */
osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_NULL, 0, 0);
+ /* Add/update SI10. */
+ if (conn->vgcs_chan.call)
+ si10_update(conn->vgcs_chan.call);
/* Report failure to MSC. */
bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
break;
--
To view, visit
https://gerrit.osmocom.org/c/osmo-bsc/+/34626?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Icd3101e6dd935a57f003253aaef400c2cf95a0c3
Gerrit-Change-Number: 34626
Gerrit-PatchSet: 7
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged