jolly has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmo-bsc/+/34626?usp=email )


Change subject: ASCI: Add System Information 10 support
......................................................................

ASCI: Add System Information 10 support

A timer is used to wait some seconds before sending SI 10 to all BTS.
This ensures that all channels are established by the MSC, before
sending a complete list of VGCS/VBS neighbor cells for a call.

For each BTS, an SI 10 is gerated with all other neighbor BTS.

The SI 10 will only define neighbor cells within the same BSC, because
it does not know about neighbor cells within other BSCs.

Change-Id: Icd3101e6dd935a57f003253aaef400c2cf95a0c3
---
M include/osmocom/bsc/gsm_data.h
M include/osmocom/bsc/system_information.h
M src/osmo-bsc/system_information.c
M src/osmo-bsc/vgcs_fsm.c
4 files changed, 313 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/26/34626/1

diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 275e4f1..7c6df9f 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -436,6 +436,8 @@
                bool msc_ack;
                /* List of VGCS/VBS "resource controling" connections */
                struct llist_head chan_list;
+               /* Timer to send SI 10 */
+               struct osmo_timer_list si10_timer;
        } vgcs_call;

        /* VGCS/VBS "resource controling" connection */
diff --git a/include/osmocom/bsc/system_information.h 
b/include/osmocom/bsc/system_information.h
index f74ef6d..f8f79a4 100644
--- a/include/osmocom/bsc/system_information.h
+++ b/include/osmocom/bsc/system_information.h
@@ -11,6 +11,7 @@
 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(uint8_t *data, size_t len, 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..f03b95b 100644
--- a/src/osmo-bsc/system_information.c
+++ b/src/osmo-bsc/system_information.c
@@ -1246,6 +1246,265 @@
        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(uint8_t *data, size_t len, struct 
gsm_subscriber_connection *conn)
+{
+       struct gsm48_system_information_type_10 *si10 = (struct 
gsm48_system_information_type_10*)data;
+       struct bitvec *nbv;
+       struct gsm_bts *s_bts = conn->lchan->ts->trx->bts, *n_bts, *l_bts;
+       int i, last_i;
+       int arfcn;
+       bool any_neighbor = false;
+       unsigned int save_cur_bit;
+       struct gsm_subscriber_connection *c;
+       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 seperate 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;
+
+       for (i = 0; i < 32; 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;
+                       if (c->lchan->ts->trx->bts->c0->arfcn != arfcn)
+                               continue;
+                       n_bts = c->lchan->ts->trx->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 differenctial 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..0b3ba91 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))

@@ -66,6 +67,9 @@
                                                     : ("VBS callref %s, cell 
%s: " fmt), \
             gsm44068_group_id_string(conn->vgcs_chan.call_ref), 
conn->vgcs_chan.ci_str, ##args)

+#define SI10_TIMER     3, 0
+#define SI10_LENGTH    21
+
 const char *gsm44068_group_id_string(uint32_t callref)
 {
        static char string[9];
@@ -129,6 +133,27 @@
  * VGCS call FSM
  */

+static void si10_timer_cb(void *data)
+{
+       struct gsm_subscriber_connection *conn = data, *c;
+       uint8_t si10[SI10_LENGTH];
+       int rc;
+
+       LOG_CALL(conn, LOGL_DEBUG, "SI 10 timer fires, sending SI 10 towards 
BTS.\n");
+
+       /* Go through all channels. */
+       llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list) {
+               /* There is an lchan! */
+               OSMO_ASSERT(c->lchan);
+               /* Encode SI 10 for this channel. Skip, if it fails. */
+               rc = gsm_generate_si10(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, 
SI10_LENGTH);
+       }
+}
+
 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;
@@ -150,6 +175,9 @@

        /* Remove pointer of FSM. */
        conn->vgcs_call.fi = NULL;
+
+       /* Stop SI 10 timer, if running. */
+       osmo_timer_del(&conn->vgcs_call.si10_timer);
 }

 static void vgcs_call_fsm_null(struct osmo_fsm_inst *fi, uint32_t event, void 
*data)
@@ -167,6 +195,8 @@
                conn->vgcs_call.ff.as_ind_link = 0;
                conn->vgcs_call.ff.bss_res = 0;
                conn->vgcs_call.ff.tcp = 0;
+               /* Start timer to send SI 10 to BTS when it fires. */
+               osmo_timer_schedule(&conn->vgcs_call.si10_timer, SI10_TIMER);
                /* Acknowlege the call. */
                bsc_tx_setup_ack(conn, &conn->vgcs_call.ff);
                break;
@@ -550,6 +580,9 @@
        /* Init L3 queue. */
        INIT_LLIST_HEAD(&conn->vgcs_call.l3_queue);

+       /* Setup timer. */
+       osmo_timer_setup(&conn->vgcs_call.si10_timer, si10_timer_cb, conn);
+
        osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_SETUP, NULL);
        return 0;
 reject:

--
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: 1
Gerrit-Owner: jolly <andr...@eversberg.eu>
Gerrit-MessageType: newchange

Reply via email to