Osmocom Packet control Unit (PCU): Network-side GPRS (RLC/MAC); BTS- or BSC-colocated https://osmocom.org/projects/osmopcu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
osmo-pcu/src/pcu_l1_if.cpp

1146 lines
36 KiB

/* pcu_l1_if.cpp
*
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* 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>
#include <unistd.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <ctype.h>
extern "C" {
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/gsmtap.h>
#include <osmocom/core/bitvec.h>
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gsm/l1sap.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm48_rest_octets.h>
#include <osmocom/gsm/sysinfo.h>
Support Neighbor Address Resolution over PCUIF IPA multiplex While NACC was initially developed, it became clear there was need for a way to interact PCU<->BSC in order resolve ARFCN+BSIC into CGI-PS for later RIM usage. Hence, this resolution was first (until today) implemented using an out of bands RPC system using the CTRL interface, which required specific config to be written and matches in osmo-pcu and osmo-bsc VTY (ip+port of the CTRL interface to use). However, this has several shortcomings: * As explained above, specific configuration is required * Since recently, we do support BSC redundancy in osmo-bts. Hence the BTS may switch to a BSC other than first one. If that happened, that'd mean the CTRL interface would still point to the initially configured one, which may not be the same currently serving the PCU. During recent development of ANR related features, a similar need for PCU<->BSC was required, but this time it was decided to extend the IPA multiplex of the Abis OML connection to pass PCUIF messages, transparently forwarded to each side by the BTS. This has the advantage that connection PCU<->BTS is handled by BTS and both sides send messages transparently. Let's switch by default to using this new interface, while still maintaing the old way for a while (announcing them as deprecated) to avoid breaking existing deployments until they are upgraded to new versions of osmo-pcu and osmo-bsc. Related: SYS#4971 Change-Id: I6ad33c7ab10202840cf804dea9ba595978d0e920
1 year ago
#include <nacc_fsm.h>
}
#include <gprs_rlcmac.h>
#include <pcu_l1_if.h>
#include <gprs_debug.h>
#include <gprs_bssgp_pcu.h>
#include <osmocom/pcu/pcuif_proto.h>
#include <bts.h>
#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);
}
extern void *tall_pcu_ctx;
#define PAGING_GROUP_LEN 3
/* 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;
}
/*
* PCU messages
*/
Support Neighbor Address Resolution over PCUIF IPA multiplex While NACC was initially developed, it became clear there was need for a way to interact PCU<->BSC in order resolve ARFCN+BSIC into CGI-PS for later RIM usage. Hence, this resolution was first (until today) implemented using an out of bands RPC system using the CTRL interface, which required specific config to be written and matches in osmo-pcu and osmo-bsc VTY (ip+port of the CTRL interface to use). However, this has several shortcomings: * As explained above, specific configuration is required * Since recently, we do support BSC redundancy in osmo-bts. Hence the BTS may switch to a BSC other than first one. If that happened, that'd mean the CTRL interface would still point to the initially configured one, which may not be the same currently serving the PCU. During recent development of ANR related features, a similar need for PCU<->BSC was required, but this time it was decided to extend the IPA multiplex of the Abis OML connection to pass PCUIF messages, transparently forwarded to each side by the BTS. This has the advantage that connection PCU<->BTS is handled by BTS and both sides send messages transparently. Let's switch by default to using this new interface, while still maintaing the old way for a while (announcing them as deprecated) to avoid breaking existing deployments until they are upgraded to new versions of osmo-pcu and osmo-bsc. Related: SYS#4971 Change-Id: I6ad33c7ab10202840cf804dea9ba595978d0e920
1 year ago
/* Can be used to allocate message with non-variable size */
struct msgb *pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr)
{
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
msg = msgb_alloc(sizeof(struct gsm_pcu_if), "pcu_sock_tx");
if (!msg)
return NULL;
msgb_put(msg, sizeof(struct gsm_pcu_if));
pcu_prim = (struct gsm_pcu_if *) msg->data;
pcu_prim->msg_type = msg_type;
pcu_prim->bts_nr = bts_nr;
return msg;
}
Support Neighbor Address Resolution over PCUIF IPA multiplex While NACC was initially developed, it became clear there was need for a way to interact PCU<->BSC in order resolve ARFCN+BSIC into CGI-PS for later RIM usage. Hence, this resolution was first (until today) implemented using an out of bands RPC system using the CTRL interface, which required specific config to be written and matches in osmo-pcu and osmo-bsc VTY (ip+port of the CTRL interface to use). However, this has several shortcomings: * As explained above, specific configuration is required * Since recently, we do support BSC redundancy in osmo-bts. Hence the BTS may switch to a BSC other than first one. If that happened, that'd mean the CTRL interface would still point to the initially configured one, which may not be the same currently serving the PCU. During recent development of ANR related features, a similar need for PCU<->BSC was required, but this time it was decided to extend the IPA multiplex of the Abis OML connection to pass PCUIF messages, transparently forwarded to each side by the BTS. This has the advantage that connection PCU<->BTS is handled by BTS and both sides send messages transparently. Let's switch by default to using this new interface, while still maintaing the old way for a while (announcing them as deprecated) to avoid breaking existing deployments until they are upgraded to new versions of osmo-pcu and osmo-bsc. Related: SYS#4971 Change-Id: I6ad33c7ab10202840cf804dea9ba595978d0e920
1 year ago
/* Allocate message with extra size, only reserve pcuif msg hdr */
static struct msgb *pcu_msgb_alloc_ext_size(uint8_t msg_type, uint8_t bts_nr, size_t extra_size)
{
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
msg = msgb_alloc(sizeof(struct gsm_pcu_if) + extra_size, "pcu_sock_tx");
/* Only header is filled, caller is responible for reserving + filling
* message type specific contents: */
msgb_put(msg, PCUIF_HDR_SIZE);
pcu_prim = (struct gsm_pcu_if *) msgb_data(msg);
pcu_prim->msg_type = msg_type;
pcu_prim->bts_nr = bts_nr;
return msg;
}
const struct value_string gsm_pcu_if_text_type_names[] = {
OSMO_VALUE_STRING(PCU_VERSION),
OSMO_VALUE_STRING(PCU_OML_ALERT),
{ 0, NULL }
};
int pcu_tx_txt_ind(enum gsm_pcu_if_text_type t, const char *fmt, ...)
{
struct gsm_pcu_if *pcu_prim;
struct gsm_pcu_if_txt_ind *txt;
va_list ap;
char *rep;
struct msgb *msg = pcu_msgb_alloc(PCU_IF_MSG_TXT_IND, 0);
if (!msg)
return -ENOMEM;
pcu_prim = (struct gsm_pcu_if *) msg->data;
txt = &pcu_prim->u.txt_ind;
txt->type = t;
va_start(ap, fmt);
rep = talloc_vasprintf(tall_pcu_ctx, fmt, ap);
va_end(ap);
if (!rep)
return -ENOMEM;
osmo_strlcpy(txt->text, rep, TXT_MAX_LEN);
talloc_free(rep);
LOGP(DL1IF, LOGL_INFO, "Sending %s TXT as %s to BTS\n", txt->text,
get_value_string(gsm_pcu_if_text_type_names, t));
return pcu_sock_send(msg);
}
static int pcu_tx_act_req(struct gprs_rlcmac_bts *bts, const struct gprs_rlcmac_pdch *pdch,
uint8_t activate)
{
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
struct gsm_pcu_if_act_req *act_req;
LOGPDCH(pdch, DL1IF, LOGL_INFO, "Sending %s request\n",
(activate) ? "activate" : "deactivate");
msg = pcu_msgb_alloc(PCU_IF_MSG_ACT_REQ, bts->nr);
if (!msg)
return -ENOMEM;
pcu_prim = (struct gsm_pcu_if *) msg->data;
act_req = &pcu_prim->u.act_req;
act_req->activate = activate;
act_req->trx_nr = pdch->trx_no();
act_req->ts_nr = pdch->ts_no;
return pcu_sock_send(msg);
}
static int pcu_tx_data_req(struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts, uint8_t sapi,
uint16_t arfcn, uint32_t fn, uint8_t block_nr, uint8_t *data,
uint8_t len)
{
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
struct gsm_pcu_if_data *data_req;
int current_fn = bts_current_frame_number(bts);
LOGP(DL1IF, LOGL_DEBUG, "(bts=%u,trx=%u,ts=%u) FN=%u Sending data request: sapi=%d "
"arfcn=%d cur_fn=%d block=%d data=%s\n", bts->nr, trx, ts, fn, sapi,
arfcn, current_fn, block_nr, osmo_hexdump(data, len));
msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_REQ, bts->nr);
if (!msg)
return -ENOMEM;
pcu_prim = (struct gsm_pcu_if *) msg->data;
data_req = &pcu_prim->u.data_req;
data_req->sapi = sapi;
data_req->fn = fn;
data_req->arfcn = arfcn;
data_req->trx_nr = trx;
data_req->ts_nr = ts;
data_req->block_nr = block_nr;
memcpy(data_req->data, data, len);
data_req->len = len;
return pcu_sock_send(msg);
}
void pcu_l1if_tx_pdtch(msgb *msg, struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr)
{
#ifdef ENABLE_DIRECT_PHY
if (bts->trx[trx].fl1h) {
l1if_pdch_req(bts->trx[trx].fl1h, ts, 0, fn, arfcn, block_nr,
msg->data, msg->len);
msgb_free(msg);
return;
}
#endif
pcu_tx_data_req(bts, trx, ts, PCU_IF_SAPI_PDTCH, arfcn, fn, block_nr,
msg->data, msg->len);
msgb_free(msg);
}
void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint16_t arfcn,
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))
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) {
l1if_pdch_req(bts->trx[trx].fl1h, ts, 1, fn, arfcn, block_nr, data, data_len);
return;
}
#endif
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)
{
uint8_t data[GSM_MACBLOCK_LEN]; /* prefix PLEN */
/* FIXME: why does OpenBTS has no PLEN and no fill in message? */
bitvec_pack(block, data + 1);
data[0] = (plen << 2) | 0x01;
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);
pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, GSM_MACBLOCK_LEN);
}
void pcu_l1if_tx_pch(struct gprs_rlcmac_bts *bts, bitvec * block, int plen, uint16_t pgroup)
{
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:
*/
OSMO_ASSERT(sizeof(data) >= PAGING_GROUP_LEN + 1 + block->data_len);
data[3] = (plen << 2) | 0x01;
bitvec_pack(block, data + PAGING_GROUP_LEN + 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);
pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, PAGING_GROUP_LEN + GSM_MACBLOCK_LEN);
}
Support Neighbor Address Resolution over PCUIF IPA multiplex While NACC was initially developed, it became clear there was need for a way to interact PCU<->BSC in order resolve ARFCN+BSIC into CGI-PS for later RIM usage. Hence, this resolution was first (until today) implemented using an out of bands RPC system using the CTRL interface, which required specific config to be written and matches in osmo-pcu and osmo-bsc VTY (ip+port of the CTRL interface to use). However, this has several shortcomings: * As explained above, specific configuration is required * Since recently, we do support BSC redundancy in osmo-bts. Hence the BTS may switch to a BSC other than first one. If that happened, that'd mean the CTRL interface would still point to the initially configured one, which may not be the same currently serving the PCU. During recent development of ANR related features, a similar need for PCU<->BSC was required, but this time it was decided to extend the IPA multiplex of the Abis OML connection to pass PCUIF messages, transparently forwarded to each side by the BTS. This has the advantage that connection PCU<->BTS is handled by BTS and both sides send messages transparently. Let's switch by default to using this new interface, while still maintaing the old way for a while (announcing them as deprecated) to avoid breaking existing deployments until they are upgraded to new versions of osmo-pcu and osmo-bsc. Related: SYS#4971 Change-Id: I6ad33c7ab10202840cf804dea9ba595978d0e920
1 year ago
int pcu_tx_neigh_addr_res_req(struct gprs_rlcmac_bts *bts, const struct neigh_cache_entry_key *neigh_key)
{
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
struct gsm_pcu_if_neigh_addr_req *naddr_req;
LOGP(DL1IF, LOGL_DEBUG, "(bts=%u) Tx Neighbor Address Resolution Request: " NEIGH_CACHE_ENTRY_KEY_FMT "\n",
bts->nr, NEIGH_CACHE_ENTRY_KEY_ARGS(neigh_key));
msg = pcu_msgb_alloc_ext_size(PCU_IF_MSG_CONTAINER, bts->nr, sizeof(struct gsm_pcu_if_neigh_addr_req));
if (!msg)
return -ENOMEM;
pcu_prim = (struct gsm_pcu_if *) msgb_data(msg);
naddr_req = (struct gsm_pcu_if_neigh_addr_req *)&pcu_prim->u.container.data[0];
msgb_put(msg, sizeof(pcu_prim->u.container) + sizeof(struct gsm_pcu_if_neigh_addr_req));
pcu_prim->u.container.msg_type = PCU_IF_MSG_NEIGH_ADDR_REQ;
osmo_store16be(sizeof(struct gsm_pcu_if_neigh_addr_req), &pcu_prim->u.container.length);
osmo_store16be(neigh_key->local_lac, &naddr_req->local_lac);
osmo_store16be(neigh_key->local_ci, &naddr_req->local_ci);
osmo_store16be(neigh_key->tgt_arfcn, &naddr_req->tgt_arfcn);
naddr_req->tgt_bsic = neigh_key->tgt_bsic;
return pcu_sock_send(msg);
}
void pcu_rx_block_time(struct gprs_rlcmac_bts *bts, uint16_t arfcn, uint32_t fn, uint8_t ts_no)
{
bts_set_current_block_frame_number(bts, fn);
}
int pcu_rx_data_ind_pdtch(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_pdch *pdch, uint8_t *data,
uint8_t len, uint32_t fn, struct pcu_l1_meas *meas)
{
int rc;
if (!pdch->is_enabled()) {
LOGPDCH(pdch, DL1IF, LOGL_INFO, "Received DATA.ind (PDTCH) on disabled TS\n");
return -EINVAL;
}
rc = pdch->rcv_block(data, len, fn, meas);
pdch_ulc_expire_fn(pdch->ulc, fn);
return rc;
}
static int list_arfcn(const struct gprs_rlcmac_bts *bts, const struct gsm_sysinfo_freq *freq, const char *text)
{
int n = 0, i;
for (i = 0; i < 1024; i++) {
if (freq[i].mask) {
if (!n)
LOGP(DL1IF, LOGL_INFO, "BTS%d: %s", bts->nr, text);
LOGPC(DL1IF, LOGL_INFO, " %d", i);
n++;
}
}
if (n)
LOGPC(DL1IF, LOGL_INFO, "\n");
return n;
}
static int pcu_rx_data_ind_bcch(struct gprs_rlcmac_bts *bts, uint8_t *data, uint8_t len)
{
struct gsm48_system_information_type_2 *si2;
const uint8_t *si_ro;
switch (len) {
case 0:
/* Due to historical reasons also accept a completely empty message as
* revoke command for SI13. */
LOGP(DL1IF, LOGL_ERROR,
"Received PCU data indication that contains no data -- Revoked SI13.\n");
bts->si13_is_set = false;
return 0;
case 1:
/* Revoke SI, type is identified by a single byte which is coded after
* enum osmo_sysinfo_type. */
switch (data[0]) {
case SYSINFO_TYPE_1:
bts->si1_is_set = false;
break;
case SYSINFO_TYPE_2:
bts->si2_is_set = false;
break;
case SYSINFO_TYPE_3:
bts->si3_is_set = false;
break;
case SYSINFO_TYPE_13:
bts->si13_is_set = false;
break;
default:
LOGP(DL1IF, LOGL_ERROR,
"Received PCU data indication that contains an unsupported system information identifier (%02x,OSMO) -- ignored.\n", data[0]);
return -EINVAL;
}
LOGP(DPCU, LOGL_DEBUG,
"Received PCU data indication: Revoked SI%s\n",
get_value_string(osmo_sitype_strs, data[0]));
return 0;
case GSM_MACBLOCK_LEN:
/* Update SI, type is identified by the RR sysinfo type, which is the
* 3rd byte in the buffer. */
switch (data[2]) {
case GSM48_MT_RR_SYSINFO_1:
memcpy(bts->si1, data, GSM_MACBLOCK_LEN);
bts->si1_is_set = true;
break;
case GSM48_MT_RR_SYSINFO_2:
memcpy(bts->si2, data, GSM_MACBLOCK_LEN);
bts->si2_is_set = true;
si2 = (struct gsm48_system_information_type_2 *)bts->si2;
gsm48_decode_freq_list(bts->si2_bcch_cell_list, si2->bcch_frequency_list,
sizeof(si2->bcch_frequency_list), 0xce, 1);
list_arfcn(bts, bts->si2_bcch_cell_list, "SI2 Neighbour cells in same band:");
break;
case GSM48_MT_RR_SYSINFO_3:
memcpy(bts->si3, data, GSM_MACBLOCK_LEN);
bts->si3_is_set = true;
break;
case GSM48_MT_RR_SYSINFO_13:
memcpy(bts->si13, data, GSM_MACBLOCK_LEN);
bts->si13_is_set = true;
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");
break;
default:
LOGP(DL1IF, LOGL_ERROR,
"Received PCU data indication that contains an unsupported system information identifier (%02x,RR) -- ignored.\n", data[2]);
return -EINVAL;
}
LOGP(DPCU, LOGL_DEBUG,
"Received PCU data indication: Updated %s: %s\n",
gsm48_pdisc_msgtype_name(data[1], data[2]),
osmo_hexdump_nospc(data + 1, GSM_MACBLOCK_LEN));
return 0;
default:
LOGP(DL1IF, LOGL_ERROR,
"Received PCU data indication with unexpected data length: %u -- ignored.\n",
len);
return -EINVAL;
}
}
static int pcu_rx_data_ind(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_data *data_ind)
{
int rc;
int current_fn = bts_current_frame_number(bts);
struct pcu_l1_meas meas = {0};
struct gprs_rlcmac_pdch *pdch;
uint8_t gsmtap_chantype;
LOGP(DL1IF, LOGL_DEBUG, "(bts=%" PRIu8 ",trx=%" PRIu8 ",ts=%" PRIu8 ") FN=%u "
"Rx DATA.ind: sapi=%d arfcn=%d cur_fn=%d "
"block=%d data=%s\n", bts->nr, data_ind->trx_nr, data_ind->ts_nr,
data_ind->fn, data_ind->sapi, data_ind->arfcn, current_fn,
data_ind->block_nr, osmo_hexdump(data_ind->data, data_ind->len));
switch (data_ind->sapi) {
case PCU_IF_SAPI_PDTCH:
pdch = &bts->trx[data_ind->trx_nr].pdch[data_ind->ts_nr];
pcu_l1_meas_set_rssi(&meas, data_ind->rssi);
/* convert BER to % value */
pcu_l1_meas_set_ber(&meas, data_ind->ber10k / 100);
pcu_l1_meas_set_bto(&meas, data_ind->ta_offs_qbits);
pcu_l1_meas_set_link_qual(&meas, data_ind->lqual_cb / 10);
LOGPDCH(pdch, DL1IF, LOGL_DEBUG, "FN=%u Rx DATA.ind PDTCH: "
"BER10k = %d, BTO = %d, Q = %d\n", data_ind->fn,
data_ind->ber10k, data_ind->ta_offs_qbits, data_ind->lqual_cb);
rc = pcu_rx_data_ind_pdtch(bts, pdch, data_ind->data, data_ind->len,
data_ind->fn, &meas);
gsmtap_chantype = GSMTAP_CHANNEL_PDTCH;
break;
case PCU_IF_SAPI_BCCH:
rc = pcu_rx_data_ind_bcch(bts, data_ind->data, data_ind->len);
gsmtap_chantype = GSMTAP_CHANNEL_BCCH;
break;
default:
LOGP(DL1IF, LOGL_ERROR, "(bts=%" PRIu8 ",trx=%" PRIu8 ",ts=%" PRIu8 ") "
"FN=%u Rx DATA.ind with unsupported sapi %d\n",
bts->nr, data_ind->trx_nr, data_ind->ts_nr, data_ind->fn, data_ind->sapi);
rc = -EINVAL;
gsmtap_chantype = GSMTAP_CHANNEL_UNKNOWN;
}
if (rc < 0 && (the_pcu->gsmtap_categ_mask & (1 <<PCU_GSMTAP_C_UL_UNKNOWN))) {
gsmtap_send(the_pcu->gsmtap, data_ind->arfcn | GSMTAP_ARFCN_F_UPLINK, data_ind->ts_nr,
gsmtap_chantype, 0, data_ind->fn, meas.rssi, meas.link_qual, data_ind->data, data_ind->len);
}
return rc;
}
static int pcu_rx_data_cnf(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_data *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);
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);
break;
default:
LOGP(DL1IF, LOGL_ERROR, "Received PCU data confirm with "
"unsupported sapi %d\n", data_cnf->sapi);
rc = -EINVAL;
}
return rc;
}
// FIXME: remove this, when changed from c++ to c.
int pcu_rx_rts_req_pdtch(struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts,
uint32_t fn, uint8_t block_nr)
{
return gprs_rlcmac_rcv_rts_block(bts,
trx, ts, fn, block_nr);
}
int pcu_rx_rts_req_ptcch(struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts,
uint32_t fn, uint8_t block_nr)
{
struct gprs_rlcmac_pdch *pdch;
/* Prevent buffer overflow */
if (trx >= ARRAY_SIZE(bts->trx) || ts >= 8)
return -EINVAL;
/* Make sure PDCH time-slot is enabled */
pdch = &bts->trx[trx].pdch[ts];
if (!pdch->m_is_enabled)
return -EAGAIN;
pcu_l1if_tx_ptcch(bts, trx, ts, bts->trx[trx].arfcn, fn, block_nr,
pdch->ptcch_msg, GSM_MACBLOCK_LEN);
return 0;
}
static int pcu_rx_rts_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_rts_req *rts_req)
{
int rc = 0;
int current_fn = bts_current_frame_number(bts);
const struct gprs_rlcmac_pdch *pdch;
pdch = &bts->trx[rts_req->trx_nr].pdch[rts_req->ts_nr];
LOGPDCH(pdch, DL1IF, LOGL_DEBUG, "FN=%u RX RTS.req: sapi=%d "
"arfcn=%d cur_fn=%d block=%d\n", rts_req->fn,
rts_req->sapi, rts_req->arfcn, current_fn, rts_req->block_nr);
switch (rts_req->sapi) {
case PCU_IF_SAPI_PDTCH:
pcu_rx_rts_req_pdtch(bts, rts_req->trx_nr, rts_req->ts_nr,
rts_req->fn, rts_req->block_nr);
break;
case PCU_IF_SAPI_PTCCH:
pcu_rx_rts_req_ptcch(bts, rts_req->trx_nr, rts_req->ts_nr,
rts_req->fn, rts_req->block_nr);
break;
default:
LOGP(DL1IF, LOGL_ERROR, "(bts=%u,trx=%u,ts=%u) FN=%u RX RTS.req with "
"unsupported sapi %d\n", bts->nr, rts_req->trx_nr, rts_req->ts_nr,
rts_req->fn, rts_req->sapi);
rc = -EINVAL;
}
return rc;
}
/* C -> C++ adapter for direct DSP 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 = {
/* The content of RA is not of interest on PTCCH/U */
.burst_type = GSM_L1_BURST_TYPE_ACCESS_0,
.is_11bit = false,
.ra = 0x00,
.trx_nr = trx_nr,
.ts_nr = ts_nr,
.rfn = fn,
.qta = qta,
};
return bts_rcv_ptcch_rach(bts, &rip);
}
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);
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,