diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h index d7c4bbf38..970fb1bfd 100644 --- a/include/osmo-bts/bts.h +++ b/include/osmo-bts/bts.h @@ -48,6 +48,7 @@ int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt int is_ag_res); uint8_t *bts_sysinfo_get(struct gsm_bts *bts, const struct gsm_time *g_time); +void regenerate_si3_restoctets(struct gsm_bts *bts); uint8_t *lchan_sacch_get(struct gsm_lchan *lchan); int lchan_init_lapdm(struct gsm_lchan *lchan); diff --git a/include/osmo-bts/gsm_data_shared.h b/include/osmo-bts/gsm_data_shared.h index 415e6bc00..90772e222 100644 --- a/include/osmo-bts/gsm_data_shared.h +++ b/include/osmo-bts/gsm_data_shared.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -620,6 +621,10 @@ struct gsm_bts { /* offsets used while generating SI2quater */ size_t e_offset; size_t u_offset; + /* decoded SI3 rest octets - *unmodified* as received from BSC */ + struct osmo_gsm48_si_ro_info si3_ro_decoded; + /* is SI3 GPRS Indicator currently disabled due to lack of PCU connection? */ + bool si3_gprs_ind_disabled; /* ip.accesss Unit ID's have Site/BTS/TRX layout */ union { diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index e4f2d6614..39b456824 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -1,6 +1,6 @@ /* pcu_sock.c: Connect from PCU via unix domain socket */ -/* (C) 2008-2010 by Harald Welte +/* (C) 2008-2019 by Harald Welte * (C) 2009-2012 by Andreas Eversberg * (C) 2012 by Holger Hans Peter Freyther * All Rights Reserved @@ -598,6 +598,9 @@ static int pcu_rx_txt_ind(struct gsm_bts *bts, oml_tx_failure_event_rep(&bts->gprs.cell.mo, NM_SEVER_CEASED, OSMO_EVT_PCU_VERS, txt->text); osmo_strlcpy(bts->pcu_version, txt->text, MAX_VERSION_LENGTH); + /* patch SI3 to advertise GPRS, *if* the SI3 sent by BSC said so */ + regenerate_si3_restoctets(bts); + if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_13)) return pcu_tx_si13(bts, true); @@ -741,6 +744,9 @@ static void pcu_sock_close(struct pcu_sock_state *state) bfd->fd = -1; osmo_fd_unregister(bfd); + /* patch SI3 to remove GPRS indicator */ + regenerate_si3_restoctets(bts); + /* re-enable the generation of ACCEPT for new connections */ state->listen_bfd.when |= BSC_FD_READ; diff --git a/src/common/rsl.c b/src/common/rsl.c index f76a006b7..b96182ff2 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -1,7 +1,7 @@ /* GSM TS 08.58 RSL, BTS Side */ /* (C) 2011 by Andreas Eversberg - * (C) 2011-2017 by Harald Welte + * (C) 2011-2019 by Harald Welte * * All Rights Reserved * @@ -360,12 +360,18 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg) bts->si_valid |= (1 << osmo_si); - if (SYSINFO_TYPE_3 == osmo_si && trx->nr == 0 && - num_agch(trx, "RSL") != 1) { - lchan_deactivate(&trx->bts->c0->ts[0].lchan[CCCH_LCHAN]); - /* will be reactivated by sapi_deactivate_cb() */ - trx->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind = - LCHAN_REL_ACT_REACT; + if (SYSINFO_TYPE_3 == osmo_si) { + if (trx->nr == 0 && num_agch(trx, "RSL") != 1) { + lchan_deactivate(&trx->bts->c0->ts[0].lchan[CCCH_LCHAN]); + /* will be reactivated by sapi_deactivate_cb() */ + trx->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind = + LCHAN_REL_ACT_REACT; + } + /* decode original SI3 Rest Octets as sent by BSC */ + osmo_gsm48_rest_octets_si3_decode(&bts->si3_ro_decoded, GSM_BTS_SI(bts, osmo_si)); + /* patch out GPRS indicator from binary if PCU is not connected; will be enabled + * after PCU connects */ + regenerate_si3_restoctets(bts); } if (SYSINFO_TYPE_13 == osmo_si) @@ -387,6 +393,8 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg) get_value_string(osmo_sitype_strs, osmo_si)); if (SYSINFO_TYPE_13 == osmo_si) pcu_tx_si13(trx->bts, false); + if (SYSINFO_TYPE_3 == osmo_si) + memset(&bts->si3_ro_decoded, 0, sizeof(bts->si3_ro_decoded)); } osmo_signal_dispatch(SS_GLOBAL, S_NEW_SYSINFO, bts); diff --git a/src/common/sysinfo.c b/src/common/sysinfo.c index e4a05c87f..c41f9d6e3 100644 --- a/src/common/sysinfo.c +++ b/src/common/sysinfo.c @@ -1,4 +1,4 @@ -/* (C) 2011 by Harald Welte +/* (C) 2011-2019 by Harald Welte * * All Rights Reserved * @@ -24,6 +24,7 @@ #include #include +#include /* properly increment SI2q index and return SI2q data for scheduling */ static inline uint8_t *get_si2q_inc_index(struct gsm_bts *bts) @@ -175,3 +176,36 @@ uint8_t *lchan_sacch_get(struct gsm_lchan *lchan) LOGPLCHAN(lchan, DL1P, LOGL_NOTICE, "SACCH no SI available\n"); return NULL; } + +/* re-generate SI3 restoctets with GPRS indicator depending on the PCU socket connection state */ +void regenerate_si3_restoctets(struct gsm_bts *bts) +{ + uint8_t *si3_buf = GSM_BTS_SI(bts, SYSINFO_TYPE_3); + size_t si3_size = offsetof(struct gsm48_system_information_type_3, rest_octets); + struct osmo_gsm48_si_ro_info si3ro_tmp; + + /* If BSC has never set SI3, there's nothing to patch */ + if (!GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_3)) + return; + + /* If SI3 from BSC doesn't have a GPRS indicator, we won't have anything to patch */ + if (!bts->si3_ro_decoded.gprs_ind.present) + return; + + /* Create a temporary copy and patch that, if no PCU is around */ + si3ro_tmp = bts->si3_ro_decoded; + if (!pcu_connected()) { + if (!bts->si3_gprs_ind_disabled) + LOGP(DPCU, LOGL_NOTICE, "Disabling GPRS Indicator in SI3 (No PCU connected)\n"); + bts->si3_gprs_ind_disabled = true; + si3ro_tmp.gprs_ind.present = 0; + } else { + if (bts->si3_gprs_ind_disabled) + LOGP(DPCU, LOGL_NOTICE, "Enabling GPRS Indicator in SI3 (PCU connected)\n"); + bts->si3_gprs_ind_disabled = false; + si3ro_tmp.gprs_ind.present = 1; /* is a no-op as we copy from bts->si3_ro_decoded */ + } + + /* re-generate the binary SI3 rest octets */ + osmo_gsm48_rest_octets_si3_encode(si3_buf + si3_size, &si3ro_tmp); +}