diff options
Diffstat (limited to 'src/pcu_l1_if.cpp')
-rw-r--r-- | src/pcu_l1_if.cpp | 342 |
1 files changed, 236 insertions, 106 deletions
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 8d9defc1..fb44bd83 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> @@ -44,8 +40,10 @@ extern "C" { #include <osmocom/gsm/protocol/gsm_04_08.h> #include <osmocom/gsm/gsm48_rest_octets.h> #include <osmocom/gsm/sysinfo.h> +#include <osmocom/gsm/gsm0502.h> #include <nacc_fsm.h> +#include <pcu_l1_if_phy.h> } #include <gprs_rlcmac.h> @@ -57,41 +55,26 @@ extern "C" { #include <pdch.h> #include <tbf_ul.h> #include <tbf_dl.h> -#include <gprs_ms_storage.h> - -// FIXME: move this, when changed from c++ to c. -extern "C" { -void *l1if_open_pdch(uint8_t trx_no, uint32_t hlayer1, - struct gsmtap_inst *gsmtap); -int l1if_connect_pdch(void *obj, uint8_t ts); -int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, - uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len); -} +#include <gprs_ms.h> extern void *tall_pcu_ctx; -#define PAGING_GROUP_LEN 3 +struct e1_ccu_conn_pars { + struct llist_head entry; -/* returns [0,999] on success, > 999 on error */ -uint16_t imsi2paging_group(const char* imsi) -{ - uint16_t pgroup = 0; - size_t len; - - len = (imsi != NULL) ? strlen(imsi) : 0; - if (len < PAGING_GROUP_LEN) - return 0xFFFF; - imsi += len - PAGING_GROUP_LEN; - - while (*imsi != '\0') { - if (!isdigit(*imsi)) - return 0xFFFF; - pgroup *= 10; - pgroup += *imsi - '0'; - imsi++; - } - return pgroup; -} + /* Related air interface */ + uint8_t bts_nr; + uint8_t trx_nr; + uint8_t ts_nr; + + /* E1 communication parameter */ + struct e1_conn_pars e1_conn_pars; +}; + +/* List storage to collect E1 connection information that we receive through the pcu_sock. The collected data serves as + * a lookup table so that we can lookup the E1 connection information for each PDCH (trx number and timeslot number) + * when it is needed. */ +static LLIST_HEAD(e1_ccu_table); /* * PCU messages @@ -248,7 +231,7 @@ void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts, uint32_t fn, uint8_t block_nr, uint8_t *data, size_t data_len) { - if (the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PTCCH)) + if (data_len && the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PTCCH)) gsmtap_send(the_pcu->gsmtap, arfcn, ts, GSMTAP_CHANNEL_PTCCH, 0, fn, 0, 0, data, data_len); #ifdef ENABLE_DIRECT_PHY if (bts->trx[trx].fl1h) { @@ -266,43 +249,49 @@ void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts, pcu_tx_data_req(bts, trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr, data, data_len); } -void pcu_l1if_tx_agch(struct gprs_rlcmac_bts *bts, bitvec * block, int plen) +/* Send a MAC block via the access grant channel. This will (obviously) only work for MAC blocks that contain + * an IMMEDIATE ASSIGNMENT. In case the confirm flag is set, the receiving end is required to send a confirmation + * back when the IMMEDIATE ASSIGNMENT has been sent. */ +void pcu_l1if_tx_agch2(struct gprs_rlcmac_bts *bts, bitvec *block, int plen, bool confirm, uint32_t msg_id) { - uint8_t data[GSM_MACBLOCK_LEN]; /* prefix PLEN */ + struct gsm_pcu_if_agch agch = { 0 }; - /* FIXME: why does OpenBTS has no PLEN and no fill in message? */ - bitvec_pack(block, data + 1); - data[0] = (plen << 2) | 0x01; + agch.confirm = confirm; + agch.msg_id = msg_id; + agch.data[0] = (plen << 2) | 0x01; + bitvec_pack(block, agch.data + 1); if (the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_AGCH)) - gsmtap_send(the_pcu->gsmtap, 0, 0, GSMTAP_CHANNEL_AGCH, 0, 0, 0, 0, data, GSM_MACBLOCK_LEN); + gsmtap_send(the_pcu->gsmtap, 0, 0, GSMTAP_CHANNEL_AGCH, 0, 0, 0, 0, agch.data, GSM_MACBLOCK_LEN); - pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, GSM_MACBLOCK_LEN); + pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_AGCH_2, 0, 0, 0, (uint8_t*)&agch, sizeof(agch)); } -void pcu_l1if_tx_pch(struct gprs_rlcmac_bts *bts, bitvec * block, int plen, uint16_t pgroup) +/* Send a MAC block via the paging channel. This will (obviously) only work for MAC blocks that contain an + * IMMEDIATE ASSIGNMENT or a PAGING COMMAND message. In case the MAC block contains an IMMEDIATE ASSIGNMENT + * message, the receiving end is required to confirm when the IMMEDIATE ASSIGNMENT has been sent. */ +void pcu_l1if_tx_pch2(struct gprs_rlcmac_bts *bts, struct bitvec *block, int plen, bool confirm, + const char *imsi, uint32_t msg_id) { - uint8_t data[PAGING_GROUP_LEN + GSM_MACBLOCK_LEN]; - int i; - - /* prepend paging group */ - for (i = 0; i < PAGING_GROUP_LEN; i++) { - data[PAGING_GROUP_LEN - 1 - i] = '0' + (char)(pgroup % 10); - pgroup = pgroup / 10; - } - OSMO_ASSERT(pgroup == 0); - - /* block provided by upper layer comes without first byte (plen), - * prepend it manually: + struct gsm_pcu_if_pch pch = { 0 }; + + pch.msg_id = msg_id; + if (imsi) + OSMO_STRLCPY_ARRAY(pch.imsi, imsi); + /* OS#6097: if strlen(pch.imsi) == 0: We assume the MS is in non-DRX + * mode (TS 44.060 5.5.1.5) and hence it is listening on all CCCH blocks + * (TS 45.002 6.5.3, 6.5.6). */ - OSMO_ASSERT(sizeof(data) >= PAGING_GROUP_LEN + 1 + block->data_len); - data[3] = (plen << 2) | 0x01; - bitvec_pack(block, data + PAGING_GROUP_LEN + 1); + + pch.confirm = confirm; + pch.data[0] = (plen << 2) | 0x01; + bitvec_pack(block, pch.data + 1); if (the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PCH)) - gsmtap_send(the_pcu->gsmtap, 0, 0, GSMTAP_CHANNEL_PCH, 0, 0, 0, 0, data + 3, GSM_MACBLOCK_LEN); + gsmtap_send(the_pcu->gsmtap, 0, 0, GSMTAP_CHANNEL_PCH, 0, 0, 0, 0, + pch.data, GSM_MACBLOCK_LEN); - pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, PAGING_GROUP_LEN + GSM_MACBLOCK_LEN); + pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_PCH_2, 0, 0, 0, (uint8_t*)&pch, sizeof(pch)); } int pcu_tx_neigh_addr_res_req(struct gprs_rlcmac_bts *bts, const struct neigh_cache_entry_key *neigh_key) @@ -342,6 +331,9 @@ int pcu_rx_data_ind_pdtch(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_pdch * { int rc; + /* First of all, update TDMA clock: */ + bts_set_current_frame_number(bts, fn); + if (!pdch->is_enabled()) { LOGPDCH(pdch, DL1IF, LOGL_INFO, "Received DATA.ind (PDTCH) on disabled TS\n"); return -EINVAL; @@ -434,6 +426,13 @@ static int pcu_rx_data_ind_bcch(struct gprs_rlcmac_bts *bts, uint8_t *data, uint si_ro = ((struct gsm48_system_information_type_13*)data)->rest_octets; if (osmo_gsm48_rest_octets_si13_decode(&bts->si13_ro_decoded, si_ro) < 0) LOGP(DPCU, LOGL_ERROR, "Error decoding SI13\n"); + /* Update our cached timers from it: */ + osmo_tdef_set(bts->T_defs_bts, 3168, bts->si13_ro_decoded.cell_opts.t3168, OSMO_TDEF_MS); + osmo_tdef_set(bts->T_defs_bts, 3192, bts->si13_ro_decoded.cell_opts.t3192, OSMO_TDEF_MS); + /* Some sanity checks: */ + if (bts->si13_ro_decoded.cell_opts.t3192 >= + osmo_tdef_get(bts->T_defs_bts, 3193, OSMO_TDEF_MS, -1)) + LOGP(DL1IF, LOGL_ERROR, "Timers incorrectly configured! T3192 >= T3193\n"); break; default: LOGP(DL1IF, LOGL_ERROR, @@ -504,22 +503,19 @@ static int pcu_rx_data_ind(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_data * return rc; } -static int pcu_rx_data_cnf(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_data *data_cnf) +static int pcu_rx_data_cnf2(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_data_cnf *data_cnf) { int rc = 0; - int current_fn = bts_current_frame_number(bts); - LOGP(DL1IF, LOGL_DEBUG, "Data confirm received: sapi=%d fn=%d cur_fn=%d\n", - data_cnf->sapi, data_cnf->fn, current_fn); + LOGP(DL1IF, LOGL_DEBUG, "Data confirm received: sapi=%d\n", data_cnf->sapi); switch (data_cnf->sapi) { - case PCU_IF_SAPI_PCH: - if (data_cnf->data[2] == 0x3f) - bts_rcv_imm_ass_cnf(bts, data_cnf->data, data_cnf->fn); + case PCU_IF_SAPI_PCH_2: + case PCU_IF_SAPI_AGCH_2: + bts_rcv_imm_ass_cnf(bts, NULL, data_cnf->msg_id); break; default: - LOGP(DL1IF, LOGL_ERROR, "Received PCU data confirm with " - "unsupported sapi %d\n", data_cnf->sapi); + LOGP(DL1IF, LOGL_ERROR, "Received PCU data confirm with unsupported sapi %d\n", data_cnf->sapi); rc = -EINVAL; } @@ -544,7 +540,7 @@ int pcu_rx_rts_req_ptcch(struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts, /* Make sure PDCH time-slot is enabled */ pdch = &bts->trx[trx].pdch[ts]; - if (!pdch->m_is_enabled) + if (!pdch_is_enabled(pdch)) return -EAGAIN; /* If there's no TBF attached to this PDCH, we can skip Tx of PTCCH @@ -555,11 +551,10 @@ int pcu_rx_rts_req_ptcch(struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts, const unsigned num_tbfs = pdch->num_tbfs(GPRS_RLCMAC_DL_TBF) + pdch->num_tbfs(GPRS_RLCMAC_UL_TBF); bool skip_idle = (num_tbfs == 0); -#ifdef ENABLE_DIRECT_PHY - /* In DIRECT_PHY mode we want to always submit something to L1 in - * TRX0, since BTS is not preparing dummy bursts on idle TS for us: */ + + if (bts->gen_idle_blocks_C0) skip_idle = skip_idle && trx != 0; -#endif + if (skip_idle) { pcu_l1if_tx_ptcch(bts, trx, ts, bts->trx[trx].arfcn, fn, block_nr, NULL, 0); @@ -601,7 +596,7 @@ static int pcu_rx_rts_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_rts_req return rc; } -/* C -> C++ adapter for direct DSP access code (e.g. osmo-bts-sysmo) */ +/* C -> C++ adapter for direct PHY access code (e.g. osmo-bts-sysmo) */ extern "C" int pcu_rx_rach_ind_ptcch(struct gprs_rlcmac_bts *bts, uint8_t trx_nr, uint8_t ts_nr, uint32_t fn, int16_t qta) { struct rach_ind_params rip = { @@ -611,7 +606,8 @@ extern "C" int pcu_rx_rach_ind_ptcch(struct gprs_rlcmac_bts *bts, uint8_t trx_nr .ra = 0x00, .trx_nr = trx_nr, .ts_nr = ts_nr, - .rfn = fn, + .rfn = fn2rfn(fn), + .fn = fn, .qta = qta, }; @@ -621,11 +617,28 @@ extern "C" int pcu_rx_rach_ind_ptcch(struct gprs_rlcmac_bts *bts, uint8_t trx_nr static int pcu_rx_rach_ind(struct gprs_rlcmac_bts *bts, const struct gsm_pcu_if_rach_ind *rach_ind) { int rc = 0; - int current_fn = bts_current_frame_number(bts); + uint32_t current_fn = bts_current_frame_number(bts); + uint16_t rfn; + + /* Note: If a BSC is sending a RACH req to us, it is actually forwarding it to + * us from BTS as a result of receiving an RFN (Fn % 42432) over RSL + * (see 3GPP TS 48.058, section 9.3.19). + * If a BTS is sending a RACH req to us, it may contain a full FN + * (current osmo-bts does that) instead of an RFN. + * For consistency, and taking into account the BSC case limitations, + * work always with RFNs here: + */ + rfn = fn2rfn(rach_ind->fn); + + LOGP(DL1IF, LOGL_INFO, + "RACH request received: sapi=%d qta=%d, ra=0x%02x, fn=%u (rfn=%u), cur_fn=%d, is_11bit=%d\n", + rach_ind->sapi, rach_ind->qta, rach_ind->ra, rach_ind->fn, rfn, current_fn, rach_ind->is_11bit); - LOGP(DL1IF, LOGL_INFO, "RACH request received: sapi=%d " - "qta=%d, ra=0x%02x, fn=%u, cur_fn=%d, is_11bit=%d\n", rach_ind->sapi, rach_ind->qta, - rach_ind->ra, rach_ind->fn, current_fn, rach_ind->is_11bit); + if (OSMO_UNLIKELY(rach_ind->fn > GSM_TDMA_HYPERFRAME - 1)) { + LOGP(DL1IF, LOGL_ERROR, "RACH request contains fn=%u that exceeds valid limits (0-%u) -- ignored!\n", + rach_ind->fn, GSM_TDMA_HYPERFRAME - 1); + return -EINVAL; + } struct rach_ind_params rip = { .burst_type = (enum ph_burst_type) rach_ind->burst_type, @@ -633,7 +646,8 @@ static int pcu_rx_rach_ind(struct gprs_rlcmac_bts *bts, const struct gsm_pcu_if_ .ra = rach_ind->ra, .trx_nr = rach_ind->trx_nr, .ts_nr = rach_ind->ts_nr, - .rfn = rach_ind->fn, + .rfn = rfn, + .fn = bts_rfn_to_fn(bts, rfn), .qta = rach_ind->qta, }; @@ -709,6 +723,38 @@ static int pcu_info_ind_ns(struct gprs_rlcmac_bts *bts, return gprs_ns_update_config(bts, info_ind->nsei, local, remote, nsvci, valid); } +const struct value_string gsm_pcuif_bts_model_names[] = { + { PCU_IF_BTS_MODEL_UNSPEC, "(unspecified)" }, + { PCU_IF_BTS_MODEL_LC15, "osmo-bts-lc15" }, + { PCU_IF_BTS_MODEL_OC2G, "osmo-bts-oc2g" }, + { PCU_IF_BTS_MODEL_OCTPHY, "osmo-bts-octphy" }, + { PCU_IF_BTS_MODEL_SYSMO, "osmo-bts-sysmo" }, + { PCU_IF_BTS_MODEL_TRX, "osmo-bts-trx" }, + { PCU_IF_BTS_MODEL_RBS, "ericsson-rbs" }, + { 0, NULL } +}; + +static bool decide_gen_idle_blocks(struct gprs_rlcmac_bts *bts) +{ + switch (bts->bts_model) { + case PCU_IF_BTS_MODEL_UNSPEC: + case PCU_IF_BTS_MODEL_LC15: + case PCU_IF_BTS_MODEL_OC2G: + case PCU_IF_BTS_MODEL_OCTPHY: + case PCU_IF_BTS_MODEL_SYSMO: + case PCU_IF_BTS_MODEL_RBS: + /* The BTS models above do not generate dummy blocks by themselves, so OsmoPCU must fill the idle gaps in the + * stream of generated PDCH blocks with dummy blocks. */ + return true; + case PCU_IF_BTS_MODEL_TRX: + /* The BTS models above generate dummy blocks by themselves, so OsmoBTS will only generate PDCH bloks that + * actually contain data. On idle, no blocks are generated. */ + return false; + default: + return false; + } +} + static int pcu_rx_info_ind(struct gprs_rlcmac_bts *bts, const struct gsm_pcu_if_info_ind *info_ind) { struct gprs_bssgp_pcu *pcu; @@ -716,14 +762,18 @@ static int pcu_rx_info_ind(struct gprs_rlcmac_bts *bts, const struct gsm_pcu_if_ unsigned int trx_nr, ts_nr; unsigned int i; + if (llist_count(&the_pcu->bts_list) > 1) + LOGP(DL1IF, LOGL_ERROR, "more than one BTS regsitered at this PCU. This PCU has only been tested with one BTS! OS#5930\n"); + + LOGP(DL1IF, LOGL_DEBUG, "Info indication received:\n"); + if (info_ind->version != PCU_IF_VERSION) { - fprintf(stderr, "PCU interface version number of BTS (%u) is " - "different (%u).\nPlease re-compile!\n", + fprintf(stderr, "PCU interface version number of BTS/BSC (%u) is different (%u).\nPlease use a BTS/BSC with a compatble interface!\n", info_ind->version, PCU_IF_VERSION); exit(-1); } - LOGP(DL1IF, LOGL_DEBUG, "Info indication received:\n"); + the_pcu->pcu_if_version = info_ind->version; if (!(info_ind->flags & PCU_IF_FLAG_ACTIVE)) { LOGP(DL1IF, LOGL_NOTICE, "BTS not available\n"); @@ -735,7 +785,8 @@ bssgp_failed: for (trx_nr = 0; trx_nr < ARRAY_SIZE(bts->trx); trx_nr++) { bts->trx[trx_nr].arfcn = info_ind->trx[trx_nr].arfcn; for (ts_nr = 0; ts_nr < ARRAY_SIZE(bts->trx[0].pdch); ts_nr++) - bts->trx[trx_nr].pdch[ts_nr].disable(); + if (bts->trx[trx_nr].pdch[ts_nr].is_enabled()) + bts->trx[trx_nr].pdch[ts_nr].disable(); } gprs_bssgp_destroy(bts); exit(0); @@ -841,23 +892,23 @@ bssgp_failed: for (trx_nr = 0; trx_nr < ARRAY_SIZE(bts->trx); trx_nr++) { bts->trx[trx_nr].arfcn = info_ind->trx[trx_nr].arfcn; - if ((info_ind->flags & PCU_IF_FLAG_SYSMO) + if ((info_ind->flags & PCU_IF_FLAG_DIRECT_PHY) && info_ind->trx[trx_nr].hlayer1) { #ifdef ENABLE_DIRECT_PHY LOGP(DL1IF, LOGL_DEBUG, " TRX %d hlayer1=%x\n", trx_nr, info_ind->trx[trx_nr].hlayer1); if (!bts->trx[trx_nr].fl1h) - bts->trx[trx_nr].fl1h = l1if_open_pdch( - trx_nr, + bts->trx[trx_nr].fl1h = l1if_open_trx( + bts->nr, trx_nr, info_ind->trx[trx_nr].hlayer1, the_pcu->gsmtap); if (!bts->trx[trx_nr].fl1h) { LOGP(DL1IF, LOGL_FATAL, "Failed to open direct " - "DSP access for PDCH.\n"); + "PHY access for PDCH.\n"); exit(0); } #else - LOGP(DL1IF, LOGL_FATAL, "Compiled without direct DSP " + LOGP(DL1IF, LOGL_FATAL, "Compiled without direct PHY " "access for PDCH, but enabled at " "BTS. Please deactivate it!\n"); exit(0); @@ -865,14 +916,14 @@ bssgp_failed: } for (ts_nr = 0; ts_nr < ARRAY_SIZE(bts->trx[0].pdch); ts_nr++) { - const struct gsm_pcu_if_info_ts *its = &info_ind->trx[trx_nr].ts[ts_nr]; + const struct gsm_pcu_if_info_trx_ts *its = &info_ind->trx[trx_nr].ts[ts_nr]; struct gprs_rlcmac_pdch *pdch = &bts->trx[trx_nr].pdch[ts_nr]; if ((info_ind->trx[trx_nr].pdch_mask & (1 << ts_nr))) { /* FIXME: activate dynamically at RLCMAC */ if (!pdch->is_enabled()) { #ifdef ENABLE_DIRECT_PHY if ((info_ind->flags & - PCU_IF_FLAG_SYSMO)) + PCU_IF_FLAG_DIRECT_PHY)) l1if_connect_pdch( bts->trx[trx_nr].fl1h, ts_nr); #endif @@ -883,7 +934,7 @@ bssgp_failed: pdch->tsc = its->tsc; /* (Optional) frequency hopping parameters */ - if (its->h) { + if (its->hopping) { pdch->fh.enabled = true; pdch->fh.maio = its->maio; pdch->fh.hsn = its->hsn; @@ -902,6 +953,10 @@ bssgp_failed: trx_nr, ts_nr, pdch->tsc, pdch->fh.enabled ? "yes" : "no"); } else { if (pdch->is_enabled()) { +#ifdef ENABLE_DIRECT_PHY + if ((info_ind->flags & PCU_IF_FLAG_DIRECT_PHY)) + l1if_disconnect_pdch(bts->trx[trx_nr].fl1h, ts_nr); +#endif pcu_tx_act_req(bts, pdch, 0); pdch->disable(); } @@ -909,16 +964,85 @@ bssgp_failed: } } + LOGP(DL1IF, LOGL_INFO, "BTS model: %s\n", get_value_string(gsm_pcuif_bts_model_names, info_ind->bts_model)); + bts->bts_model = info_ind->bts_model; + bts->gen_idle_blocks_C0 = decide_gen_idle_blocks(bts); + bts->active = true; return rc; } -static int pcu_rx_time_ind(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_time_ind *time_ind) +/* Query E1 CCU connection parameters by TS and TRX number */ +int pcu_l1if_get_e1_ccu_conn_pars(struct e1_conn_pars **e1_conn_pars, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr) +{ + struct e1_ccu_conn_pars *e1_ccu_conn_pars; + + llist_for_each_entry(e1_ccu_conn_pars, &e1_ccu_table, entry) { + if (e1_ccu_conn_pars->bts_nr == bts_nr && e1_ccu_conn_pars->trx_nr == trx_nr + && e1_ccu_conn_pars->ts_nr == ts_nr) { + *e1_conn_pars = &e1_ccu_conn_pars->e1_conn_pars; + return 0; + } + } + + return -EINVAL; +} + +/* Allocate a new connection parameter struct and store connection parameters */ +static void new_e1_ccu_conn_pars(const struct gsm_pcu_if_e1_ccu_ind *e1_ccu_ind, uint8_t bts_nr) +{ + struct e1_ccu_conn_pars *e1_ccu_conn_pars; + + e1_ccu_conn_pars = talloc_zero(tall_pcu_ctx, struct e1_ccu_conn_pars); + OSMO_ASSERT(e1_ccu_conn_pars); + e1_ccu_conn_pars->bts_nr = bts_nr; + e1_ccu_conn_pars->trx_nr = e1_ccu_ind->trx_nr; + e1_ccu_conn_pars->ts_nr = e1_ccu_ind->ts_nr; + e1_ccu_conn_pars->e1_conn_pars.e1_nr = e1_ccu_ind->e1_nr; + e1_ccu_conn_pars->e1_conn_pars.e1_ts = e1_ccu_ind->e1_ts; + e1_ccu_conn_pars->e1_conn_pars.e1_ts_ss = e1_ccu_ind->e1_ts_ss; + llist_add(&e1_ccu_conn_pars->entry, &e1_ccu_table); +} + +static int pcu_rx_e1_ccu_ind(struct gprs_rlcmac_bts *bts, const struct gsm_pcu_if_e1_ccu_ind *e1_ccu_ind) { - uint8_t fn13 = time_ind->fn % 13; + struct e1_conn_pars *e1_conn_pars; + uint8_t rate; + uint8_t subslot_nr; + int rc; + + /* only used with log statement below, no technical relevance otherwise. */ + if (e1_ccu_ind->e1_ts_ss > 3) { + rate = 64; + subslot_nr = 0; + } else { + rate = 16; + subslot_nr = e1_ccu_ind->e1_ts_ss; + } + + LOGP(DL1IF, LOGL_NOTICE, + "(ts=%u,trx=%u) new E1 CCU communication parameters for CCU (E1-line:%u, E1-TS:%u, E1-SS:%u, rate:%ukbps)\n", + e1_ccu_ind->ts_nr, e1_ccu_ind->trx_nr, e1_ccu_ind->e1_nr, e1_ccu_ind->e1_ts, + subslot_nr, rate); + + /* Search for an existing entry, when found, update it. */ + rc = pcu_l1if_get_e1_ccu_conn_pars(&e1_conn_pars, bts->nr, e1_ccu_ind->trx_nr, e1_ccu_ind->ts_nr); + if (rc == 0) { + e1_conn_pars->e1_nr = e1_ccu_ind->e1_nr; + e1_conn_pars->e1_ts = e1_ccu_ind->e1_ts; + e1_conn_pars->e1_ts_ss = e1_ccu_ind->e1_ts_ss; + return 0; + } + + /* Create new connection parameter entry */ + new_e1_ccu_conn_pars(e1_ccu_ind, bts->nr); + return 0; +} +static int pcu_rx_time_ind(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_time_ind *time_ind) +{ /* omit frame numbers not starting at a MAC block */ - if (fn13 != 0 && fn13 != 4 && fn13 != 8) + if (!fn_valid(time_ind->fn)) return 0; LOGP(DL1IF, LOGL_DEBUG, "Time indication received: %d\n", time_ind->fn % 52); @@ -961,7 +1085,7 @@ static int pcu_rx_pag_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_pag_req case GSM_MI_TYPE_IMSI: req.mi_imsi = mi; req.mi_imsi_present = true; - ms = bts_ms_by_imsi(bts, req.mi_imsi.imsi); + ms = bts_get_ms_by_imsi(bts, req.mi_imsi.imsi); break; default: LOGP(DL1IF, LOGL_ERROR, "Unexpected MI type %u\n", mi.type); @@ -984,7 +1108,7 @@ static int pcu_rx_susp_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_susp_r LOGP(DL1IF, LOGL_INFO, "GPRS Suspend request received: TLLI=0x%08x RAI=%s\n", susp_req->tlli, osmo_rai_name(&ra_id)); - if ((ms = bts_ms_store(bts)->get_ms(susp_req->tlli))) { + if ((ms = bts_get_ms_by_tlli(bts, susp_req->tlli, GSM_RESERVED_TMSI))) { /* We need to catch both pointers here since MS may become freed after first tbf_free(dl_tbf) if only DL TBF was available */ dl_tbf = ms_dl_tbf(ms); @@ -1009,8 +1133,8 @@ static int pcu_rx_app_info_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_ap app_info_req->application_type, app_info_req->len); bts->app_info_pending = 0; - llist_for_each(tmp, bts_ms_store(bts)->ms_list()) { - GprsMs *ms = llist_entry(tmp, typeof(*ms), list); + llist_for_each(tmp, &bts->ms_list) { + struct GprsMs *ms = llist_entry(tmp, typeof(*ms), list); if (!ms_dl_tbf(ms)) continue; bts->app_info_pending++; @@ -1067,8 +1191,8 @@ static int pcu_rx_neigh_addr_cnf(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_ NEIGH_CACHE_ENTRY_KEY_ARGS(&neigh_key), naddr_cnf->err_code); } - llist_for_each(tmp, bts_ms_store(bts)->ms_list()) { - GprsMs *ms = llist_entry(tmp, typeof(*ms), list); + llist_for_each(tmp, &bts->ms_list) { + struct GprsMs *ms = llist_entry(tmp, typeof(*ms), list); if (ms->nacc && nacc_fsm_is_waiting_addr_resolution(ms->nacc, &neigh_key)) osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_RX_RAC_CI, cgi_ps_ptr); } @@ -1125,9 +1249,9 @@ int pcu_rx(struct gsm_pcu_if *pcu_prim, size_t pcu_prim_length) CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.data_ind); rc = pcu_rx_data_ind(bts, &pcu_prim->u.data_ind); break; - case PCU_IF_MSG_DATA_CNF: - CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.data_cnf); - rc = pcu_rx_data_cnf(bts, &pcu_prim->u.data_cnf); + case PCU_IF_MSG_DATA_CNF_2: + CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.data_cnf2); + rc = pcu_rx_data_cnf2(bts, &pcu_prim->u.data_cnf2); break; case PCU_IF_MSG_RTS_REQ: CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.rts_req); @@ -1141,6 +1265,10 @@ int pcu_rx(struct gsm_pcu_if *pcu_prim, size_t pcu_prim_length) CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.info_ind); rc = pcu_rx_info_ind(bts, &pcu_prim->u.info_ind); break; + case PCU_IF_MSG_E1_CCU_IND: + CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.e1_ccu_ind); + rc = pcu_rx_e1_ccu_ind(bts, &pcu_prim->u.e1_ccu_ind); + break; case PCU_IF_MSG_TIME_IND: CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.time_ind); rc = pcu_rx_time_ind(bts, &pcu_prim->u.time_ind); @@ -1167,6 +1295,8 @@ int pcu_rx(struct gsm_pcu_if *pcu_prim, size_t pcu_prim_length) if (pcu_prim_length < exp_len) { LOGP(DL1IF, LOGL_ERROR, "Received %zu bytes on PCU Socket, but primitive container size" \ "is %zu, discarding\n", pcu_prim_length, exp_len); + rc = -EINVAL; + break; } rc = pcu_rx_container(bts, &pcu_prim->u.container); break; |