2012-03-05 15:24:57 +00:00
|
|
|
/* pcu_l1_if.cpp
|
|
|
|
*
|
2012-07-12 10:49:15 +00:00
|
|
|
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
|
2012-03-05 15:24:57 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
2019-12-09 12:55:12 +00:00
|
|
|
#include <inttypes.h>
|
2012-07-12 10:49:15 +00:00
|
|
|
#include <stdlib.h>
|
2012-06-23 08:33:16 +00:00
|
|
|
#include <string.h>
|
2012-07-12 10:49:15 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <assert.h>
|
2012-06-23 08:33:16 +00:00
|
|
|
#include <sys/socket.h>
|
2012-07-12 10:49:15 +00:00
|
|
|
#include <sys/un.h>
|
2013-03-16 15:16:41 +00:00
|
|
|
#include <arpa/inet.h>
|
2020-03-26 13:47:13 +00:00
|
|
|
#include <ctype.h>
|
2018-01-26 12:31:42 +00:00
|
|
|
|
2012-06-23 08:33:16 +00:00
|
|
|
extern "C" {
|
|
|
|
#include <osmocom/core/talloc.h>
|
2012-07-12 10:49:15 +00:00
|
|
|
#include <osmocom/core/select.h>
|
|
|
|
#include <osmocom/core/msgb.h>
|
2016-02-22 10:42:33 +00:00
|
|
|
#include <osmocom/core/gsmtap_util.h>
|
|
|
|
#include <osmocom/core/gsmtap.h>
|
2018-01-26 12:31:42 +00:00
|
|
|
#include <osmocom/core/bitvec.h>
|
2020-09-16 19:52:02 +00:00
|
|
|
#include <osmocom/core/sockaddr_str.h>
|
2018-01-26 12:31:42 +00:00
|
|
|
#include <osmocom/core/logging.h>
|
|
|
|
#include <osmocom/core/utils.h>
|
2020-10-12 00:27:22 +00:00
|
|
|
#include <osmocom/gprs/gprs_ns2.h>
|
2018-01-26 12:31:42 +00:00
|
|
|
#include <osmocom/gsm/l1sap.h>
|
|
|
|
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
2012-06-23 08:33:16 +00:00
|
|
|
}
|
2012-03-05 15:24:57 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
#include <gprs_rlcmac.h>
|
|
|
|
#include <pcu_l1_if.h>
|
|
|
|
#include <gprs_debug.h>
|
|
|
|
#include <gprs_bssgp_pcu.h>
|
2016-11-16 21:48:33 +00:00
|
|
|
#include <osmocom/pcu/pcuif_proto.h>
|
2013-10-17 15:01:54 +00:00
|
|
|
#include <bts.h>
|
2018-02-19 16:17:28 +00:00
|
|
|
#include <pdch.h>
|
2020-09-22 13:57:37 +00:00
|
|
|
#include <tbf_ul.h>
|
|
|
|
#include <tbf_dl.h>
|
2012-06-23 08:33:16 +00:00
|
|
|
|
2012-12-18 09:47:28 +00:00
|
|
|
// FIXME: move this, when changed from c++ to c.
|
|
|
|
extern "C" {
|
2016-05-13 08:34:15 +00:00
|
|
|
void *l1if_open_pdch(uint8_t trx_no, uint32_t hlayer1,
|
|
|
|
struct gsmtap_inst *gsmtap);
|
2012-12-18 09:47:28 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-07-13 12:00:21 +00:00
|
|
|
extern void *tall_pcu_ctx;
|
|
|
|
|
2019-12-23 11:41:34 +00:00
|
|
|
#define PAGING_GROUP_LEN 3
|
|
|
|
|
|
|
|
/* returns [0,999] on success, > 999 on error */
|
|
|
|
uint16_t imsi2paging_group(const char* imsi)
|
|
|
|
{
|
|
|
|
uint16_t pgroup = 0;
|
2020-01-15 17:25:48 +00:00
|
|
|
size_t len;
|
2019-12-23 11:41:34 +00:00
|
|
|
|
2020-01-15 17:25:48 +00:00
|
|
|
len = (imsi != NULL) ? strlen(imsi) : 0;
|
|
|
|
if (len < PAGING_GROUP_LEN)
|
2019-12-23 11:41:34 +00:00
|
|
|
return 0xFFFF;
|
|
|
|
imsi += len - PAGING_GROUP_LEN;
|
|
|
|
|
|
|
|
while (*imsi != '\0') {
|
|
|
|
if (!isdigit(*imsi))
|
|
|
|
return 0xFFFF;
|
|
|
|
pgroup *= 10;
|
|
|
|
pgroup += *imsi - '0';
|
|
|
|
imsi++;
|
|
|
|
}
|
|
|
|
return pgroup;
|
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
/*
|
|
|
|
* PCU messages
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct msgb *pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr)
|
2012-03-18 11:48:51 +00:00
|
|
|
{
|
2012-07-12 10:49:15 +00:00
|
|
|
struct msgb *msg;
|
|
|
|
struct gsm_pcu_if *pcu_prim;
|
2012-03-18 11:48:51 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
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;
|
2012-03-18 11:48:51 +00:00
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2017-03-08 17:53:30 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
static int pcu_tx_act_req(uint8_t trx, uint8_t ts, uint8_t activate)
|
2012-04-12 10:24:35 +00:00
|
|
|
{
|
2012-07-12 10:49:15 +00:00
|
|
|
struct msgb *msg;
|
|
|
|
struct gsm_pcu_if *pcu_prim;
|
|
|
|
struct gsm_pcu_if_act_req *act_req;
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "Sending %s request: trx=%d ts=%d\n",
|
|
|
|
(activate) ? "activate" : "deactivate", trx, ts);
|
|
|
|
|
|
|
|
msg = pcu_msgb_alloc(PCU_IF_MSG_ACT_REQ, 0);
|
|
|
|
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 = trx;
|
|
|
|
act_req->ts_nr = ts;
|
|
|
|
|
|
|
|
return pcu_sock_send(msg);
|
2012-04-12 10:24:35 +00:00
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
static int pcu_tx_data_req(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)
|
2012-03-05 15:24:57 +00:00
|
|
|
{
|
2012-07-12 10:49:15 +00:00
|
|
|
struct msgb *msg;
|
|
|
|
struct gsm_pcu_if *pcu_prim;
|
|
|
|
struct gsm_pcu_if_data *data_req;
|
2018-04-10 11:31:45 +00:00
|
|
|
int current_fn = get_current_fn();
|
2012-07-12 10:49:15 +00:00
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Sending data request: trx=%d ts=%d sapi=%d "
|
2018-04-10 11:31:45 +00:00
|
|
|
"arfcn=%d fn=%d cur_fn=%d block=%d data=%s\n", trx, ts, sapi, arfcn, fn, current_fn,
|
2012-07-12 10:49:15 +00:00
|
|
|
block_nr, osmo_hexdump(data, len));
|
|
|
|
|
|
|
|
msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_REQ, 0);
|
|
|
|
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);
|
2012-03-05 15:24:57 +00:00
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
|
|
|
|
uint32_t fn, uint8_t block_nr)
|
2012-06-29 18:53:15 +00:00
|
|
|
{
|
2017-09-01 09:00:39 +00:00
|
|
|
#ifdef ENABLE_DIRECT_PHY
|
2013-10-17 17:41:11 +00:00
|
|
|
struct gprs_rlcmac_bts *bts = bts_main_data();
|
2012-12-18 09:47:28 +00:00
|
|
|
|
2016-02-22 10:42:33 +00:00
|
|
|
if (bts->trx[trx].fl1h) {
|
2012-12-18 09:47:28 +00:00
|
|
|
l1if_pdch_req(bts->trx[trx].fl1h, ts, 0, fn, arfcn, block_nr,
|
|
|
|
msg->data, msg->len);
|
2016-02-22 10:42:33 +00:00
|
|
|
msgb_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
2012-12-18 09:47:28 +00:00
|
|
|
#endif
|
2016-02-22 10:42:33 +00:00
|
|
|
pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PDTCH, arfcn, fn, block_nr,
|
2012-12-18 09:47:28 +00:00
|
|
|
msg->data, msg->len);
|
2012-07-12 10:49:15 +00:00
|
|
|
msgb_free(msg);
|
2012-06-29 18:53:15 +00:00
|
|
|
}
|
|
|
|
|
2019-10-05 15:22:08 +00:00
|
|
|
void pcu_l1if_tx_ptcch(uint8_t trx, uint8_t ts, uint16_t arfcn,
|
|
|
|
uint32_t fn, uint8_t block_nr,
|
|
|
|
uint8_t *data, size_t data_len)
|
2012-03-05 15:24:57 +00:00
|
|
|
{
|
2013-10-17 17:41:11 +00:00
|
|
|
struct gprs_rlcmac_bts *bts = bts_main_data();
|
2012-12-18 09:47:28 +00:00
|
|
|
|
2017-08-16 22:49:23 +00:00
|
|
|
if (bts->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PTCCH))
|
2019-10-05 15:22:08 +00:00
|
|
|
gsmtap_send(bts->gsmtap, arfcn, ts, GSMTAP_CHANNEL_PTCCH, 0, fn, 0, 0, data, data_len);
|
2016-04-21 12:35:55 +00:00
|
|
|
#ifdef ENABLE_DIRECT_PHY
|
2016-02-22 10:42:33 +00:00
|
|
|
if (bts->trx[trx].fl1h) {
|
2019-10-05 15:22:08 +00:00
|
|
|
l1if_pdch_req(bts->trx[trx].fl1h, ts, 1, fn, arfcn, block_nr, data, data_len);
|
2016-02-22 10:42:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-12-18 09:47:28 +00:00
|
|
|
#endif
|
2019-10-05 15:22:08 +00:00
|
|
|
pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr, data, data_len);
|
2012-03-18 11:48:51 +00:00
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
void pcu_l1if_tx_agch(bitvec * block, int plen)
|
2012-04-17 18:00:31 +00:00
|
|
|
{
|
2019-09-30 17:07:16 +00:00
|
|
|
struct gprs_rlcmac_bts *bts = bts_main_data();
|
2019-10-07 18:56:48 +00:00
|
|
|
uint8_t data[GSM_MACBLOCK_LEN]; /* prefix PLEN */
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
/* FIXME: why does OpenBTS has no PLEN and no fill in message? */
|
|
|
|
bitvec_pack(block, data + 1);
|
|
|
|
data[0] = (plen << 2) | 0x01;
|
2019-09-30 17:07:16 +00:00
|
|
|
|
|
|
|
if (bts->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_AGCH))
|
2019-10-07 18:56:48 +00:00
|
|
|
gsmtap_send(bts->gsmtap, 0, 0, GSMTAP_CHANNEL_AGCH, 0, 0, 0, 0, data, GSM_MACBLOCK_LEN);
|
2019-09-30 17:07:16 +00:00
|
|
|
|
2019-10-07 18:56:48 +00:00
|
|
|
pcu_tx_data_req(0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, GSM_MACBLOCK_LEN);
|
2012-07-12 10:49:15 +00:00
|
|
|
}
|
2012-06-23 08:33:16 +00:00
|
|
|
|
2019-12-23 11:41:34 +00:00
|
|
|
void pcu_l1if_tx_pch(bitvec * block, int plen, uint16_t pgroup)
|
2012-07-12 10:49:15 +00:00
|
|
|
{
|
2019-09-30 17:07:16 +00:00
|
|
|
struct gprs_rlcmac_bts *bts = bts_main_data();
|
2019-10-07 18:56:02 +00:00
|
|
|
uint8_t data[PAGING_GROUP_LEN + GSM_MACBLOCK_LEN];
|
2019-12-23 11:41:34 +00:00
|
|
|
int i;
|
2012-07-12 10:49:15 +00:00
|
|
|
|
2019-10-07 18:56:02 +00:00
|
|
|
/* prepend paging group */
|
2019-12-23 11:41:34 +00:00
|
|
|
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);
|
2012-07-12 10:49:15 +00:00
|
|
|
|
2019-10-07 18:56:02 +00:00
|
|
|
/* block provided by upper layer comes without first byte (plen),
|
|
|
|
* prepend it manually:
|
|
|
|
*/
|
|
|
|
OSMO_ASSERT(sizeof(data) >= PAGING_GROUP_LEN + 1 + block->data_len);
|
2012-07-12 10:49:15 +00:00
|
|
|
data[3] = (plen << 2) | 0x01;
|
2019-10-07 18:56:02 +00:00
|
|
|
bitvec_pack(block, data + PAGING_GROUP_LEN + 1);
|
2019-09-30 17:07:16 +00:00
|
|
|
|
|
|
|
if (bts->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PCH))
|
2019-10-07 18:56:02 +00:00
|
|
|
gsmtap_send(bts->gsmtap, 0, 0, GSMTAP_CHANNEL_PCH, 0, 0, 0, 0, data + 3, GSM_MACBLOCK_LEN);
|
2019-09-30 17:07:16 +00:00
|
|
|
|
2019-10-07 18:56:02 +00:00
|
|
|
pcu_tx_data_req(0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, PAGING_GROUP_LEN + GSM_MACBLOCK_LEN);
|
2012-04-17 18:00:31 +00:00
|
|
|
}
|
|
|
|
|
2015-08-26 11:22:28 +00:00
|
|
|
extern "C" void pcu_rx_block_time(uint16_t arfcn, uint32_t fn, uint8_t ts_no)
|
|
|
|
{
|
|
|
|
BTS::main_bts()->set_current_block_frame_number(fn, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void pcu_rx_ra_time(uint16_t arfcn, uint32_t fn, uint8_t ts_no)
|
|
|
|
{
|
|
|
|
/* access bursts may arrive some bursts earlier */
|
|
|
|
BTS::main_bts()->set_current_block_frame_number(fn, 5);
|
|
|
|
}
|
|
|
|
|
2013-10-26 14:42:38 +00:00
|
|
|
extern "C" int pcu_rx_data_ind_pdtch(uint8_t trx_no, uint8_t ts_no, uint8_t *data,
|
2015-06-08 09:05:45 +00:00
|
|
|
uint8_t len, uint32_t fn, struct pcu_l1_meas *meas)
|
2012-12-18 09:47:28 +00:00
|
|
|
{
|
2013-10-26 14:42:38 +00:00
|
|
|
struct gprs_rlcmac_pdch *pdch;
|
|
|
|
|
|
|
|
pdch = &bts_main_data()->trx[trx_no].pdch[ts_no];
|
2015-06-08 09:05:45 +00:00
|
|
|
return pdch->rcv_block(data, len, fn, meas);
|
2012-12-18 09:47:28 +00:00
|
|
|
}
|
|
|
|
|
2017-09-01 09:02:40 +00:00
|
|
|
static int pcu_rx_data_ind_bcch(uint8_t *data, uint8_t len)
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_bts *bts = bts_main_data();
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
bts->si13_is_set = false;
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "Received PCU data indication with empty SI13: cache cleaned\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len != GSM_MACBLOCK_LEN) {
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Received PCU data indication with SI13 with unexpected length %u\n", len);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(bts->si13, data, GSM_MACBLOCK_LEN);
|
|
|
|
bts->si13_is_set = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-21 19:56:23 +00:00
|
|
|
static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
|
2012-03-18 11:48:51 +00:00
|
|
|
{
|
2017-07-21 19:56:23 +00:00
|
|
|
struct gprs_rlcmac_bts *bts = bts_main_data();
|
2016-02-22 10:42:33 +00:00
|
|
|
int rc;
|
2018-04-10 11:31:45 +00:00
|
|
|
int current_fn = get_current_fn();
|
Convert GprsMS and helpers classes to C
As we integrate osmo-pcu more and more with libosmocore features, it
becomes really hard to use them since libosmocore relies heavily on C
specific compilation features, which are not available in old C++
compilers (such as designated initializers for complex types in FSMs).
GprsMs is right now a quite simple object since initial design of
osmo-pcu made it optional and most of the logic was placed and stored
duplicated in TBF objects. However, that's changing as we introduce more
features, with the GprsMS class getting more weight. Hence, let's move
it now to be a C struct in order to be able to easily use libosmocore
features there, such as FSMs.
Some helper classes which GprsMs uses are also mostly move to C since
they are mostly structs with methods, so there's no point in having
duplicated APIs for C++ and C for such simple cases.
For some more complex classes, like (ul_,dl_)tbf, C API bindings are
added where needed so that GprsMs can use functionalitites from that
class. Most of those APIs can be kept afterwards and drop the C++ ones
since they provide no benefit in general.
Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c
2020-12-16 14:59:45 +00:00
|
|
|
struct pcu_l1_meas meas = {0};
|
2020-06-30 15:57:42 +00:00
|
|
|
uint8_t gsmtap_chantype;
|
2017-09-01 09:00:39 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Data indication received: sapi=%d arfcn=%d "
|
2018-04-10 11:31:45 +00:00
|
|
|
"fn=%d cur_fn=%d block=%d data=%s\n", data_ind->sapi,
|
|
|
|
data_ind->arfcn, data_ind->fn, current_fn, data_ind->block_nr,
|
2012-07-12 10:49:15 +00:00
|
|
|
osmo_hexdump(data_ind->data, data_ind->len));
|
|
|
|
|
2012-03-18 11:48:51 +00:00
|
|
|
switch (data_ind->sapi) {
|
2012-07-12 10:49:15 +00:00
|
|
|
case PCU_IF_SAPI_PDTCH:
|
Convert GprsMS and helpers classes to C
As we integrate osmo-pcu more and more with libosmocore features, it
becomes really hard to use them since libosmocore relies heavily on C
specific compilation features, which are not available in old C++
compilers (such as designated initializers for complex types in FSMs).
GprsMs is right now a quite simple object since initial design of
osmo-pcu made it optional and most of the logic was placed and stored
duplicated in TBF objects. However, that's changing as we introduce more
features, with the GprsMS class getting more weight. Hence, let's move
it now to be a C struct in order to be able to easily use libosmocore
features there, such as FSMs.
Some helper classes which GprsMs uses are also mostly move to C since
they are mostly structs with methods, so there's no point in having
duplicated APIs for C++ and C for such simple cases.
For some more complex classes, like (ul_,dl_)tbf, C API bindings are
added where needed so that GprsMs can use functionalitites from that
class. Most of those APIs can be kept afterwards and drop the C++ ones
since they provide no benefit in general.
Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c
2020-12-16 14:59:45 +00:00
|
|
|
pcu_l1_meas_set_rssi(&meas, data_ind->rssi);
|
2017-09-01 09:00:39 +00:00
|
|
|
/* convert BER to % value */
|
Convert GprsMS and helpers classes to C
As we integrate osmo-pcu more and more with libosmocore features, it
becomes really hard to use them since libosmocore relies heavily on C
specific compilation features, which are not available in old C++
compilers (such as designated initializers for complex types in FSMs).
GprsMs is right now a quite simple object since initial design of
osmo-pcu made it optional and most of the logic was placed and stored
duplicated in TBF objects. However, that's changing as we introduce more
features, with the GprsMS class getting more weight. Hence, let's move
it now to be a C struct in order to be able to easily use libosmocore
features there, such as FSMs.
Some helper classes which GprsMs uses are also mostly move to C since
they are mostly structs with methods, so there's no point in having
duplicated APIs for C++ and C for such simple cases.
For some more complex classes, like (ul_,dl_)tbf, C API bindings are
added where needed so that GprsMs can use functionalitites from that
class. Most of those APIs can be kept afterwards and drop the C++ ones
since they provide no benefit in general.
Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c
2020-12-16 14:59:45 +00:00
|
|
|
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);
|
2019-07-09 09:16:35 +00:00
|
|
|
|
2017-09-01 09:00:39 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Data indication with raw measurements received: BER10k = %d, BTO = %d, Q = %d\n",
|
|
|
|
data_ind->ber10k, data_ind->ta_offs_qbits, data_ind->lqual_cb);
|
2019-07-09 09:16:35 +00:00
|
|
|
|
2012-12-18 09:47:28 +00:00
|
|
|
rc = pcu_rx_data_ind_pdtch(data_ind->trx_nr, data_ind->ts_nr,
|
2013-03-16 15:15:01 +00:00
|
|
|
data_ind->data, data_ind->len, data_ind->fn,
|
2015-06-08 09:05:45 +00:00
|
|
|
&meas);
|
2020-06-30 15:57:42 +00:00
|
|
|
gsmtap_chantype = GSMTAP_CHANNEL_PDTCH;
|
2012-03-18 11:48:51 +00:00
|
|
|
break;
|
2017-09-01 09:02:40 +00:00
|
|
|
case PCU_IF_SAPI_BCCH:
|
|
|
|
rc = pcu_rx_data_ind_bcch(data_ind->data, data_ind->len);
|
2020-06-30 15:57:42 +00:00
|
|
|
gsmtap_chantype = GSMTAP_CHANNEL_BCCH;
|
2017-09-01 09:02:40 +00:00
|
|
|
break;
|
2012-03-18 11:48:51 +00:00
|
|
|
default:
|
2012-07-12 10:49:15 +00:00
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Received PCU data indication with "
|
|
|
|
"unsupported sapi %d\n", data_ind->sapi);
|
|
|
|
rc = -EINVAL;
|
2020-06-30 15:57:42 +00:00
|
|
|
gsmtap_chantype = GSMTAP_CHANNEL_UNKNOWN;
|
2012-03-05 15:24:57 +00:00
|
|
|
}
|
2012-03-18 11:48:51 +00:00
|
|
|
|
2017-08-16 22:49:23 +00:00
|
|
|
if (rc < 0 && (bts->gsmtap_categ_mask & (1 <<PCU_GSMTAP_C_UL_UNKNOWN))) {
|
2017-07-21 19:56:23 +00:00
|
|
|
gsmtap_send(bts->gsmtap, data_ind->arfcn | GSMTAP_ARFCN_F_UPLINK, data_ind->ts_nr,
|
2020-06-30 15:57:42 +00:00
|
|
|
gsmtap_chantype, 0, data_ind->fn, meas.rssi, meas.link_qual, data_ind->data, data_ind->len);
|
2017-07-21 19:56:23 +00:00
|
|
|
}
|
|
|
|
|
2012-03-18 11:48:51 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-09-27 07:23:24 +00:00
|
|
|
static int pcu_rx_data_cnf(struct gsm_pcu_if_data *data_cnf)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
2018-04-10 11:31:45 +00:00
|
|
|
int current_fn = get_current_fn();
|
2012-09-27 07:23:24 +00:00
|
|
|
|
2018-04-10 11:31:45 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Data confirm received: sapi=%d fn=%d cur_fn=%d\n",
|
|
|
|
data_cnf->sapi, data_cnf->fn, current_fn);
|
2012-09-27 07:23:24 +00:00
|
|
|
|
|
|
|
switch (data_cnf->sapi) {
|
|
|
|
case PCU_IF_SAPI_PCH:
|
2012-10-08 10:30:56 +00:00
|
|
|
if (data_cnf->data[2] == 0x3f)
|
2013-10-26 17:49:16 +00:00
|
|
|
BTS::main_bts()->rcv_imm_ass_cnf(data_cnf->data, data_cnf->fn);
|
2012-09-27 07:23:24 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Received PCU data confirm with "
|
|
|
|
"unsupported sapi %d\n", data_cnf->sapi);
|
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-12-18 09:47:28 +00:00
|
|
|
// FIXME: remove this, when changed from c++ to c.
|
2016-07-20 11:05:05 +00:00
|
|
|
extern "C" int pcu_rx_rts_req_pdtch(uint8_t trx, uint8_t ts,
|
2012-12-18 09:47:28 +00:00
|
|
|
uint32_t fn, uint8_t block_nr)
|
|
|
|
{
|
2013-10-17 17:41:11 +00:00
|
|
|
return gprs_rlcmac_rcv_rts_block(bts_main_data(),
|
2016-07-20 11:05:05 +00:00
|
|
|
trx, ts, fn, block_nr);
|
2012-12-18 09:47:28 +00:00
|
|
|
}
|
2019-10-05 15:22:08 +00:00
|
|
|
extern "C" int pcu_rx_rts_req_ptcch(uint8_t trx, uint8_t ts,
|
|
|
|
uint32_t fn, uint8_t block_nr)
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_bts *bts = bts_main_data();
|
|
|
|
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(trx, ts, bts->trx[trx].arfcn, fn, block_nr,
|
|
|
|
pdch->ptcch_msg, GSM_MACBLOCK_LEN);
|
|
|
|
return 0;
|
|
|
|
}
|
2012-12-18 09:47:28 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
static int pcu_rx_rts_req(struct gsm_pcu_if_rts_req *rts_req)
|
2012-04-17 18:00:31 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
2018-04-10 11:31:45 +00:00
|
|
|
int current_fn = get_current_fn();
|
2012-04-17 18:00:31 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "RTS request received: trx=%d ts=%d sapi=%d "
|
2018-04-10 11:31:45 +00:00
|
|
|
"arfcn=%d fn=%d cur_fn=%d block=%d\n", rts_req->trx_nr, rts_req->ts_nr,
|
|
|
|
rts_req->sapi, rts_req->arfcn, rts_req->fn, current_fn, rts_req->block_nr);
|
2012-03-18 11:48:51 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
switch (rts_req->sapi) {
|
|
|
|
case PCU_IF_SAPI_PDTCH:
|
2012-12-18 09:47:28 +00:00
|
|
|
pcu_rx_rts_req_pdtch(rts_req->trx_nr, rts_req->ts_nr,
|
2016-07-20 11:05:05 +00:00
|
|
|
rts_req->fn, rts_req->block_nr);
|
2012-03-18 11:48:51 +00:00
|
|
|
break;
|
2012-07-12 10:49:15 +00:00
|
|
|
case PCU_IF_SAPI_PTCCH:
|
2019-10-05 15:22:08 +00:00
|
|
|
pcu_rx_rts_req_ptcch(rts_req->trx_nr, rts_req->ts_nr,
|
|
|
|
rts_req->fn, rts_req->block_nr);
|
2012-03-18 11:48:51 +00:00
|
|
|
break;
|
|
|
|
default:
|
2012-07-12 10:49:15 +00:00
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Received PCU RTS request with "
|
|
|
|
"unsupported sapi %d\n", rts_req->sapi);
|
|
|
|
rc = -EINVAL;
|
2012-03-18 11:48:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
2012-03-05 15:24:57 +00:00
|
|
|
}
|
2012-06-23 08:33:16 +00:00
|
|
|
|
2019-10-05 16:45:31 +00:00
|
|
|
/* C -> C++ adapter for direct DSP access code (e.g. osmo-bts-sysmo) */
|
2020-05-21 12:23:33 +00:00
|
|
|
extern "C" int pcu_rx_rach_ind_ptcch(uint8_t trx_nr, uint8_t ts_nr, uint32_t fn, int16_t qta)
|
2019-10-05 16:45:31 +00:00
|
|
|
{
|
2020-05-21 12:55:46 +00:00
|
|
|
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::main_bts()->rcv_ptcch_rach(&rip);
|
2019-10-05 16:45:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 12:55:46 +00:00
|
|
|
static int pcu_rx_rach_ind(const struct gsm_pcu_if_rach_ind *rach_ind)
|
2012-06-23 08:33:16 +00:00
|
|
|
{
|
2012-07-12 10:49:15 +00:00
|
|
|
int rc = 0;
|
2018-04-10 11:31:45 +00:00
|
|
|
int current_fn = get_current_fn();
|
2012-06-23 08:33:16 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
LOGP(DL1IF, LOGL_INFO, "RACH request received: sapi=%d "
|
2020-03-29 12:01:58 +00:00
|
|
|
"qta=%d, ra=0x%02x, fn=%u, cur_fn=%d, is_11bit=%d\n", rach_ind->sapi, rach_ind->qta,
|
2018-04-10 11:31:45 +00:00
|
|
|
rach_ind->ra, rach_ind->fn, current_fn, rach_ind->is_11bit);
|
2012-06-23 08:33:16 +00:00
|
|
|
|
2020-05-21 12:55:46 +00:00
|
|
|
struct rach_ind_params rip = {
|
|
|
|
.burst_type = (enum ph_burst_type) rach_ind->burst_type,
|
|
|
|
.is_11bit = rach_ind->is_11bit > 0,
|
|
|
|
.ra = rach_ind->ra,
|
|
|
|
.trx_nr = rach_ind->trx_nr,
|
|
|
|
.ts_nr = rach_ind->ts_nr,
|
|
|
|
.rfn = rach_ind->fn,
|
|
|
|
.qta = rach_ind->qta,
|
|
|
|
};
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
switch (rach_ind->sapi) {
|
|
|
|
case PCU_IF_SAPI_RACH:
|
2020-05-21 12:55:46 +00:00
|
|
|
rc = BTS::main_bts()->rcv_rach(&rip);
|
2012-07-12 10:49:15 +00:00
|
|
|
break;
|
2019-10-05 16:45:31 +00:00
|
|
|
case PCU_IF_SAPI_PTCCH:
|
2020-05-21 12:55:46 +00:00
|
|
|
rc = BTS::main_bts()->rcv_ptcch_rach(&rip);
|
2019-10-05 16:45:31 +00:00
|
|
|
break;
|
2012-07-12 10:49:15 +00:00
|
|
|
default:
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Received PCU rach request with "
|
|
|
|
"unsupported sapi %d\n", rach_ind->sapi);
|
|
|
|
rc = -EINVAL;
|
2012-06-23 08:33:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-10-12 00:27:22 +00:00
|
|
|
static int pcu_info_ind_ns(struct gprs_rlcmac_bts *bts,
|
|
|
|
const struct gsm_pcu_if_info_ind *info_ind)
|
|
|
|
{
|
|
|
|
struct osmo_sockaddr remote[PCU_IF_NUM_NSVC] = { };
|
|
|
|
struct osmo_sockaddr local[PCU_IF_NUM_NSVC] = { };
|
|
|
|
uint16_t nsvci[PCU_IF_NUM_NSVC] = { };
|
|
|
|
uint16_t valid = 0;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < PCU_IF_NUM_NSVC; i++) {
|
|
|
|
struct osmo_sockaddr_str sockstr;
|
|
|
|
|
|
|
|
switch (info_ind->address_type[i]) {
|
|
|
|
case PCU_IF_ADDR_TYPE_IPV4:
|
|
|
|
local[i].u.sin.sin_family = AF_INET;
|
|
|
|
local[i].u.sin.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
local[i].u.sin.sin_port = htons(info_ind->local_port[i]);
|
|
|
|
|
|
|
|
remote[i].u.sin.sin_family = AF_INET;
|
2020-10-27 12:24:40 +00:00
|
|
|
memcpy(&remote[i].u.sin.sin_addr, &info_ind->remote_ip[i].v4,
|
|
|
|
sizeof(struct in_addr));
|
2020-10-12 00:27:22 +00:00
|
|
|
remote[i].u.sin.sin_port = htons(info_ind->remote_port[i]);
|
|
|
|
break;
|
|
|
|
case PCU_IF_ADDR_TYPE_IPV6:
|
|
|
|
local[i].u.sin6.sin6_family = AF_INET6;
|
|
|
|
local[i].u.sin6.sin6_addr = in6addr_any;
|
|
|
|
local[i].u.sin6.sin6_port = htons(info_ind->local_port[i]);
|
|
|
|
|
|
|
|
remote[i].u.sin6.sin6_family = AF_INET6;
|
2020-10-27 12:24:40 +00:00
|
|
|
memcpy(&remote[i].u.sin6.sin6_addr,
|
|
|
|
&info_ind->remote_ip[i].v6,
|
|
|
|
sizeof(struct in6_addr));
|
2020-10-12 00:27:22 +00:00
|
|
|
remote[i].u.sin6.sin6_port = htons(info_ind->remote_port[i]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
nsvci[i] = info_ind->nsvci[i];
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " NS%u nsvci=%u\n", i, nsvci[i]);
|
|
|
|
if (osmo_sockaddr_str_from_sockaddr(&sockstr, &remote[i].u.sas))
|
|
|
|
strcpy(sockstr.ip, "invalid");
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " NS%u address: r=%s:%u<->l=NULL:%u\n",
|
|
|
|
i, sockstr.ip, sockstr.port, info_ind->local_port[i]);
|
|
|
|
|
|
|
|
valid |= 1 << i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (valid == 0) {
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "No NSVC available to connect to the SGSN!\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gprs_ns_config(bts, info_ind->nsei, local, remote, nsvci, valid);
|
|
|
|
}
|
|
|
|
|
2020-07-23 18:16:36 +00:00
|
|
|
static int pcu_rx_info_ind(const struct gsm_pcu_if_info_ind *info_ind)
|
2012-06-23 08:33:16 +00:00
|
|
|
{
|
2013-10-17 17:41:11 +00:00
|
|
|
struct gprs_rlcmac_bts *bts = bts_main_data();
|
2013-07-28 17:11:20 +00:00
|
|
|
struct gprs_bssgp_pcu *pcu;
|
2016-11-17 17:40:02 +00:00
|
|
|
int rc = 0;
|
2020-07-23 18:24:47 +00:00
|
|
|
unsigned int trx_nr, ts_nr;
|
2020-10-30 16:14:26 +00:00
|
|
|
unsigned int i;
|
2012-07-12 10:49:15 +00:00
|
|
|
|
2012-07-18 08:06:48 +00:00
|
|
|
if (info_ind->version != PCU_IF_VERSION) {
|
2020-07-18 19:05:33 +00:00
|
|
|
fprintf(stderr, "PCU interface version number of BTS (%u) is "
|
|
|
|
"different (%u).\nPlease re-compile!\n",
|
2012-07-18 08:06:48 +00:00
|
|
|
info_ind->version, PCU_IF_VERSION);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Info indication received:\n");
|
|
|
|
|
|
|
|
if (!(info_ind->flags & PCU_IF_FLAG_ACTIVE)) {
|
|
|
|
LOGP(DL1IF, LOGL_NOTICE, "BTS not available\n");
|
2018-02-14 18:46:33 +00:00
|
|
|
if (!bts->active)
|
|
|
|
return -EAGAIN;
|
2012-07-12 10:49:15 +00:00
|
|
|
bssgp_failed:
|
2018-02-14 18:46:33 +00:00
|
|
|
bts->active = false;
|
2012-07-12 10:49:15 +00:00
|
|
|
/* free all TBF */
|
2020-07-23 18:24:47 +00:00
|
|
|
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].free_resources();
|
2012-07-12 10:49:15 +00:00
|
|
|
}
|
2020-09-16 19:52:02 +00:00
|
|
|
gprs_bssgp_destroy(bts);
|
2014-06-04 16:30:59 +00:00
|
|
|
exit(0);
|
2012-07-12 10:49:15 +00:00
|
|
|
}
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "BTS available\n");
|
2018-02-20 23:39:07 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " mcc=%03u\n", info_ind->mcc);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " mnc=%0*u\n", info_ind->mnc_3_digits, info_ind->mnc);
|
2012-07-12 10:49:15 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " lac=%d\n", info_ind->lac);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " rac=%d\n", info_ind->rac);
|
2019-03-21 18:48:55 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " cell_id=%d\n", info_ind->cell_id);
|
2012-12-18 09:47:28 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " bsic=%d\n", info_ind->bsic);
|
2012-07-12 10:49:15 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " nsei=%d\n", info_ind->nsei);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " nse_timer=%d %d %d %d %d %d %d\n",
|
|
|
|
info_ind->nse_timer[0], info_ind->nse_timer[1],
|
|
|
|
info_ind->nse_timer[2], info_ind->nse_timer[3],
|
|
|
|
info_ind->nse_timer[4], info_ind->nse_timer[5],
|
|
|
|
info_ind->nse_timer[6]);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " cell_timer=%d %d %d %d %d %d %d %d %d %d "
|
|
|
|
"%d\n",
|
|
|
|
info_ind->cell_timer[0], info_ind->cell_timer[1],
|
|
|
|
info_ind->cell_timer[2], info_ind->cell_timer[3],
|
|
|
|
info_ind->cell_timer[4], info_ind->cell_timer[5],
|
|
|
|
info_ind->cell_timer[6], info_ind->cell_timer[7],
|
|
|
|
info_ind->cell_timer[8], info_ind->cell_timer[9],
|
|
|
|
info_ind->cell_timer[10]);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " repeat_time=%d\n", info_ind->repeat_time);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " repeat_count=%d\n", info_ind->repeat_count);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " bvci=%d\n", info_ind->bvci);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " t3142=%d\n", info_ind->t3142);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " t3169=%d\n", info_ind->t3169);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " t3191=%d\n", info_ind->t3191);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " t3193=%d (ms)\n", info_ind->t3193_10ms * 10);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " t3195=%d\n", info_ind->t3195);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " n3101=%d\n", info_ind->n3101);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " n3103=%d\n", info_ind->n3103);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " n3105=%d\n", info_ind->n3105);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " cv_countdown=%d\n", info_ind->cv_countdown);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " dl_tbf_ext=%d\n", info_ind->dl_tbf_ext);
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " ul_tbf_ext=%d\n", info_ind->ul_tbf_ext);
|
2012-12-18 09:47:28 +00:00
|
|
|
bts->bsic = info_ind->bsic;
|
2020-10-30 16:14:26 +00:00
|
|
|
|
|
|
|
bts->cs_mask = 1 << 0; /* We need at least 1 CS, let's enable CS1 */
|
2012-07-12 10:49:15 +00:00
|
|
|
for (i = 0; i < 4; i++) {
|
2020-10-30 16:14:26 +00:00
|
|
|
uint8_t allowed = !!(info_ind->flags & (PCU_IF_FLAG_CS1 << i));
|
|
|
|
bts->cs_mask |= allowed << i;
|
|
|
|
if (allowed)
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " Use CS%d\n", i + 1);
|
2012-07-12 10:49:15 +00:00
|
|
|
}
|
2020-10-30 17:35:54 +00:00
|
|
|
bts_set_max_cs(bts, bts->vty.max_cs_dl, bts->vty.max_cs_ul); /* recalc max CS values */
|
2020-10-30 16:14:26 +00:00
|
|
|
|
|
|
|
bts->mcs_mask = 0;
|
2012-07-12 10:49:15 +00:00
|
|
|
for (i = 0; i < 9; i++) {
|
2020-10-30 16:14:26 +00:00
|
|
|
uint8_t allowed = !!(info_ind->flags & (PCU_IF_FLAG_MCS1 << i));
|
|
|
|
bts->mcs_mask |= allowed << i;
|
2020-10-30 17:46:24 +00:00
|
|
|
if (allowed)
|
2020-10-30 16:14:26 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " Use MCS%d\n", i + 1);
|
2020-10-30 17:46:24 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
}
|
2020-10-30 17:35:54 +00:00
|
|
|
bts_set_max_mcs(bts, bts->vty.max_mcs_dl, bts->vty.max_mcs_ul); /* recalc max MCS values */
|
2020-10-30 16:14:26 +00:00
|
|
|
|
2020-11-03 14:59:39 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " initial_cs=%u%s\n", info_ind->initial_cs,
|
|
|
|
bts->vty.force_initial_cs ? " (VTY forced, ignoring)" : "");
|
|
|
|
if (!bts->vty.force_initial_cs) {
|
|
|
|
if (info_ind->initial_cs > bts->bts->max_cs_dl()) {
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " downgrading initial_cs_dl to %d\n", bts->bts->max_cs_dl());
|
|
|
|
bts->initial_cs_dl = bts->bts->max_cs_dl();
|
|
|
|
} else {
|
|
|
|
bts->initial_cs_dl = info_ind->initial_cs;
|
|
|
|
}
|
|
|
|
if (info_ind->initial_cs > bts->bts->max_cs_ul()) {
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " downgrading initial_cs_ul to %d\n", bts->bts->max_cs_ul());
|
|
|
|
bts->initial_cs_ul = bts->bts->max_cs_ul();
|
|
|
|
} else {
|
|
|
|
bts->initial_cs_ul = info_ind->initial_cs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " initial_mcs=%u%s\n", info_ind->initial_mcs,
|
|
|
|
bts->vty.force_initial_mcs ? " (VTY forced, ignoring)" : "");
|
|
|
|
if (!bts->vty.force_initial_mcs) {
|
|
|
|
if (info_ind->initial_mcs > bts->bts->max_mcs_dl()) {
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " downgrading initial_mcs_dl to %d\n", bts->bts->max_mcs_dl());
|
|
|
|
bts->initial_mcs_dl = bts->bts->max_mcs_dl();
|
|
|
|
} else {
|
|
|
|
bts->initial_mcs_dl = info_ind->initial_mcs;
|
|
|
|
}
|
|
|
|
if (info_ind->initial_mcs > bts->bts->max_mcs_ul()) {
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " downgrading initial_mcs_ul to %d\n", bts->bts->max_mcs_ul());
|
|
|
|
bts->initial_mcs_ul = bts->bts->max_mcs_ul();
|
|
|
|
} else {
|
|
|
|
bts->initial_mcs_ul = info_ind->initial_mcs;
|
|
|
|
}
|
2020-10-30 16:14:26 +00:00
|
|
|
}
|
2020-09-16 19:52:02 +00:00
|
|
|
|
|
|
|
pcu = gprs_bssgp_init(
|
|
|
|
bts,
|
|
|
|
info_ind->nsei, info_ind->bvci,
|
|
|
|
info_ind->mcc, info_ind->mnc, info_ind->mnc_3_digits,
|
|
|
|
info_ind->lac, info_ind->rac, info_ind->cell_id);
|
|
|
|
if (!pcu) {
|
2020-10-08 15:46:26 +00:00
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Failed to init BSSGP\n");
|
2020-07-28 11:47:18 +00:00
|
|
|
goto bssgp_failed;
|
|
|
|
}
|
|
|
|
|
2020-10-12 00:27:22 +00:00
|
|
|
rc = pcu_info_ind_ns(pcu->bts, info_ind);
|
|
|
|
if (rc < 0) {
|
2020-09-16 19:52:02 +00:00
|
|
|
LOGP(DL1IF, LOGL_ERROR, "No NSVC available to connect to the SGSN!\n");
|
2012-07-12 10:49:15 +00:00
|
|
|
goto bssgp_failed;
|
2012-06-23 08:33:16 +00:00
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
if (info_ind->t3142) { /* if timer values are set */
|
2019-09-05 12:48:35 +00:00
|
|
|
osmo_tdef_set(bts->T_defs_bts, 3142, info_ind->t3142, OSMO_TDEF_S);
|
|
|
|
osmo_tdef_set(bts->T_defs_bts, 3169, info_ind->t3169, OSMO_TDEF_S);
|
|
|
|
osmo_tdef_set(bts->T_defs_bts, 3191, info_ind->t3191, OSMO_TDEF_S);
|
|
|
|
osmo_tdef_set(bts->T_defs_bts, 3193, info_ind->t3193_10ms * 10, OSMO_TDEF_MS);
|
|
|
|
osmo_tdef_set(bts->T_defs_bts, 3195, info_ind->t3195, OSMO_TDEF_S);
|
2012-07-12 10:49:15 +00:00
|
|
|
bts->n3101 = info_ind->n3101;
|
|
|
|
bts->n3103 = info_ind->n3103;
|
|
|
|
bts->n3105 = info_ind->n3105;
|
|
|
|
}
|
|
|
|
|
2020-07-23 18:24:47 +00:00
|
|
|
for (trx_nr = 0; trx_nr < ARRAY_SIZE(bts->trx); trx_nr++) {
|
|
|
|
bts->trx[trx_nr].arfcn = info_ind->trx[trx_nr].arfcn;
|
2012-12-18 09:47:28 +00:00
|
|
|
if ((info_ind->flags & PCU_IF_FLAG_SYSMO)
|
2020-07-23 18:24:47 +00:00
|
|
|
&& info_ind->trx[trx_nr].hlayer1) {
|
2016-04-21 12:35:55 +00:00
|
|
|
#ifdef ENABLE_DIRECT_PHY
|
2020-07-23 18:24:47 +00:00
|
|
|
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,
|
|
|
|
info_ind->trx[trx_nr].hlayer1,
|
2016-02-22 10:39:30 +00:00
|
|
|
bts->gsmtap);
|
2020-07-23 18:24:47 +00:00
|
|
|
if (!bts->trx[trx_nr].fl1h) {
|
2012-12-18 09:47:28 +00:00
|
|
|
LOGP(DL1IF, LOGL_FATAL, "Failed to open direct "
|
|
|
|
"DSP access for PDCH.\n");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
LOGP(DL1IF, LOGL_FATAL, "Compiled without direct DSP "
|
|
|
|
"access for PDCH, but enabled at "
|
|
|
|
"BTS. Please deactivate it!\n");
|
|
|
|
exit(0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-07-23 18:24:47 +00:00
|
|
|
for (ts_nr = 0; ts_nr < ARRAY_SIZE(bts->trx[0].pdch); ts_nr++) {
|
2020-07-20 17:54:42 +00:00
|
|
|
const struct gsm_pcu_if_info_ts *its = &info_ind->trx[trx_nr].ts[ts_nr];
|
2020-07-23 18:28:13 +00:00
|
|
|
struct gprs_rlcmac_pdch *pdch = &bts->trx[trx_nr].pdch[ts_nr];
|
2020-07-23 18:24:47 +00:00
|
|
|
if ((info_ind->trx[trx_nr].pdch_mask & (1 << ts_nr))) {
|
2012-07-12 10:49:15 +00:00
|
|
|
/* FIXME: activate dynamically at RLCMAC */
|
2013-10-19 15:37:48 +00:00
|
|
|
if (!pdch->is_enabled()) {
|
2016-04-21 12:35:55 +00:00
|
|
|
#ifdef ENABLE_DIRECT_PHY
|
2012-12-18 09:47:28 +00:00
|
|
|
if ((info_ind->flags &
|
|
|
|
PCU_IF_FLAG_SYSMO))
|
|
|
|
l1if_connect_pdch(
|
2020-07-23 18:24:47 +00:00
|
|
|
bts->trx[trx_nr].fl1h, ts_nr);
|
2012-12-18 09:47:28 +00:00
|
|
|
#endif
|
2020-07-23 18:24:47 +00:00
|
|
|
pcu_tx_act_req(trx_nr, ts_nr, 1);
|
2013-10-19 15:37:48 +00:00
|
|
|
pdch->enable();
|
2012-07-20 09:19:59 +00:00
|
|
|
}
|
2020-07-20 17:54:42 +00:00
|
|
|
|
|
|
|
pdch->tsc = its->tsc;
|
|
|
|
|
|
|
|
/* (Optional) frequency hopping parameters */
|
|
|
|
if (its->h) {
|
|
|
|
pdch->fh.enabled = true;
|
|
|
|
pdch->fh.maio = its->maio;
|
|
|
|
pdch->fh.hsn = its->hsn;
|
|
|
|
|
|
|
|
OSMO_ASSERT(its->ma_bit_len <= sizeof(pdch->fh.ma) * 8);
|
|
|
|
pdch->fh.ma_oct_len = OSMO_BYTES_FOR_BITS(its->ma_bit_len);
|
|
|
|
pdch->fh.ma_bit_len = its->ma_bit_len;
|
|
|
|
|
|
|
|
/* Mobile Allocation + padding (byte/bit order as on the wire):
|
|
|
|
* | 00 00 00 00 00 cc bb aa | -> | cc bb aa 00 00 00 00 00 | */
|
|
|
|
unsigned int offset = sizeof(pdch->fh.ma) - pdch->fh.ma_oct_len;
|
|
|
|
memcpy(pdch->fh.ma, its->ma + offset, pdch->fh.ma_oct_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "PDCH (trx=%u, ts=%u): tsc=%u, hopping=%s\n",
|
|
|
|
trx_nr, ts_nr, pdch->tsc, pdch->fh.enabled ? "yes" : "no");
|
2012-07-12 10:49:15 +00:00
|
|
|
} else {
|
2013-10-19 15:37:48 +00:00
|
|
|
if (pdch->is_enabled()) {
|
2020-07-23 18:24:47 +00:00
|
|
|
pcu_tx_act_req(trx_nr, ts_nr, 0);
|
2013-10-20 14:37:05 +00:00
|
|
|
pdch->free_resources();
|
2013-10-19 15:37:48 +00:00
|
|
|
pdch->disable();
|
2012-07-20 09:19:59 +00:00
|
|
|
}
|
2012-07-12 10:49:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-07-06 06:58:22 +00:00
|
|
|
|
2018-02-14 18:46:33 +00:00
|
|
|
bts->active = true;
|
2012-07-12 10:49:15 +00:00
|
|
|
return rc;
|
2012-06-23 08:33:16 +00:00
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
|
2012-06-23 08:33:16 +00:00
|
|
|
{
|
2012-07-12 10:49:15 +00:00
|
|
|
uint8_t fn13 = time_ind->fn % 13;
|
|
|
|
|
|
|
|
/* omit frame numbers not starting at a MAC block */
|
|
|
|
if (fn13 != 0 && fn13 != 4 && fn13 != 8)
|
|
|
|
return 0;
|
2017-06-26 10:10:12 +00:00
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Time indication received: %d\n", time_ind->fn % 52);
|
2012-07-12 10:49:15 +00:00
|
|
|
|
2013-10-17 17:59:56 +00:00
|
|
|
BTS::main_bts()->set_current_frame_number(time_ind->fn);
|
2012-06-23 08:33:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-19 11:06:26 +00:00
|
|
|
static int pcu_rx_pag_req(struct gsm_pcu_if_pag_req *pag_req)
|
|
|
|
{
|
paging: pass struct osmo_mobile_identity, not encoded IE bytes
In get_paging_mi(), before this, an encoded buffer of Mobile Identity bytes is
returned. Code paths following this repeatedly decode the Mobile Identity
bytes, e.g. for logging. Also, in get_paging_mi(), since the TMSI is read in
from a different encoding than a typical Mobile Identity IE, the TMSI was
manually encoded into a typical Mobile Identity IE. This is essentially a code
dup of osmo_mobile_identity_encode(). Stop this madness.
Instead, in get_paging_mi(), return a decoded struct osmo_mobile_identity. Code
paths after this use the struct osmo_mobile_identity directly without repeated
decoding.
At the point of finally needing an encoded Mobile Identity IE (in
Encoding::write_paging_request()), do a proper osmo_mobile_identity_encode().
Since this may return errors, add an rc check for the caller of
write_paging_request(), gprs_rlcmac_paging_request().
A side effect is stricter validation of the Mobile Identity passing through the
Paging code path. Before, invalid MI might have passed through unnoticed.
Change-Id: Iad845acb0096b75dc453105c9c16b2252879b4ca
2020-08-21 14:21:23 +00:00
|
|
|
struct osmo_mobile_identity mi;
|
|
|
|
int rc;
|
|
|
|
|
2012-07-19 11:06:26 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Paging request received: chan_needed=%d "
|
|
|
|
"length=%d\n", pag_req->chan_needed, pag_req->identity_lv[0]);
|
|
|
|
|
2019-12-09 12:55:12 +00:00
|
|
|
/* check if identity does not fit: length > sizeof(lv) - 1 */
|
|
|
|
if (pag_req->identity_lv[0] >= sizeof(pag_req->identity_lv)) {
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Paging identity too large (%" PRIu8 ")\n",
|
|
|
|
pag_req->identity_lv[0]);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
paging: pass struct osmo_mobile_identity, not encoded IE bytes
In get_paging_mi(), before this, an encoded buffer of Mobile Identity bytes is
returned. Code paths following this repeatedly decode the Mobile Identity
bytes, e.g. for logging. Also, in get_paging_mi(), since the TMSI is read in
from a different encoding than a typical Mobile Identity IE, the TMSI was
manually encoded into a typical Mobile Identity IE. This is essentially a code
dup of osmo_mobile_identity_encode(). Stop this madness.
Instead, in get_paging_mi(), return a decoded struct osmo_mobile_identity. Code
paths after this use the struct osmo_mobile_identity directly without repeated
decoding.
At the point of finally needing an encoded Mobile Identity IE (in
Encoding::write_paging_request()), do a proper osmo_mobile_identity_encode().
Since this may return errors, add an rc check for the caller of
write_paging_request(), gprs_rlcmac_paging_request().
A side effect is stricter validation of the Mobile Identity passing through the
Paging code path. Before, invalid MI might have passed through unnoticed.
Change-Id: Iad845acb0096b75dc453105c9c16b2252879b4ca
2020-08-21 14:21:23 +00:00
|
|
|
rc = osmo_mobile_identity_decode(&mi, &pag_req->identity_lv[1], pag_req->identity_lv[0], true);
|
|
|
|
if (rc < 0) {
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Failed to decode Mobile Identity in Paging Request (rc=%d)\n", rc);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return BTS::main_bts()->add_paging(pag_req->chan_needed, &mi);
|
2012-07-19 11:06:26 +00:00
|
|
|
}
|
|
|
|
|
2017-07-10 22:06:38 +00:00
|
|
|
static int pcu_rx_susp_req(struct gsm_pcu_if_susp_req *susp_req)
|
|
|
|
{
|
2020-09-22 13:57:37 +00:00
|
|
|
BTS *bts = BTS::main_bts();
|
2017-07-10 22:06:38 +00:00
|
|
|
struct bssgp_bvc_ctx *bctx = gprs_bssgp_pcu_current_bctx();
|
2020-09-22 13:57:37 +00:00
|
|
|
GprsMs *ms;
|
|
|
|
struct gprs_rlcmac_dl_tbf *dl_tbf;
|
|
|
|
struct gprs_rlcmac_ul_tbf *ul_tbf;
|
2017-07-10 22:06:38 +00:00
|
|
|
struct gprs_ra_id ra_id;
|
|
|
|
|
|
|
|
gsm48_parse_ra(&ra_id, susp_req->ra_id);
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "GPRS Suspend request received: TLLI=0x%08x RAI=%s\n",
|
|
|
|
susp_req->tlli, osmo_rai_name(&ra_id));
|
|
|
|
|
2020-09-22 13:57:37 +00:00
|
|
|
if ((ms = bts->ms_store().get_ms(susp_req->tlli))) {
|
|
|
|
/* We need to catch both pointers here since MS may become freed
|
|
|
|
after first tbf_free(dl_tbf) if only DL TBF was available */
|
Convert GprsMS and helpers classes to C
As we integrate osmo-pcu more and more with libosmocore features, it
becomes really hard to use them since libosmocore relies heavily on C
specific compilation features, which are not available in old C++
compilers (such as designated initializers for complex types in FSMs).
GprsMs is right now a quite simple object since initial design of
osmo-pcu made it optional and most of the logic was placed and stored
duplicated in TBF objects. However, that's changing as we introduce more
features, with the GprsMS class getting more weight. Hence, let's move
it now to be a C struct in order to be able to easily use libosmocore
features there, such as FSMs.
Some helper classes which GprsMs uses are also mostly move to C since
they are mostly structs with methods, so there's no point in having
duplicated APIs for C++ and C for such simple cases.
For some more complex classes, like (ul_,dl_)tbf, C API bindings are
added where needed so that GprsMs can use functionalitites from that
class. Most of those APIs can be kept afterwards and drop the C++ ones
since they provide no benefit in general.
Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c
2020-12-16 14:59:45 +00:00
|
|
|
dl_tbf = ms_dl_tbf(ms);
|
|
|
|
ul_tbf = ms_ul_tbf(ms);
|
2020-09-22 13:57:37 +00:00
|
|
|
if (dl_tbf)
|
|
|
|
tbf_free(dl_tbf);
|
|
|
|
if (ul_tbf)
|
|
|
|
tbf_free(ul_tbf);
|
|
|
|
}
|
|
|
|
|
2017-07-10 22:06:38 +00:00
|
|
|
if (!bctx)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return bssgp_tx_suspend(bctx->nsei, susp_req->tlli, &ra_id);
|
|
|
|
}
|
|
|
|
|
2019-09-05 15:13:33 +00:00
|
|
|
static int pcu_rx_app_info_req(struct gsm_pcu_if_app_info_req *app_info_req)
|
|
|
|
{
|
|
|
|
BTS *bts = BTS::main_bts();
|
|
|
|
struct gprs_rlcmac_bts *bts_data = bts->bts_data();
|
2021-01-14 11:12:43 +00:00
|
|
|
struct llist_head *tmp;
|
2019-09-05 15:13:33 +00:00
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Application Information Request received: type=0x%08x len=%i\n",
|
|
|
|
app_info_req->application_type, app_info_req->len);
|
|
|
|
|
|
|
|
bts_data->app_info_pending = 0;
|
2021-01-14 11:12:43 +00:00
|
|
|
llist_for_each(tmp, bts->ms_store().ms_list()) {
|
|
|
|
GprsMs *ms = llist_entry(tmp, typeof(*ms), list);
|
Convert GprsMS and helpers classes to C
As we integrate osmo-pcu more and more with libosmocore features, it
becomes really hard to use them since libosmocore relies heavily on C
specific compilation features, which are not available in old C++
compilers (such as designated initializers for complex types in FSMs).
GprsMs is right now a quite simple object since initial design of
osmo-pcu made it optional and most of the logic was placed and stored
duplicated in TBF objects. However, that's changing as we introduce more
features, with the GprsMS class getting more weight. Hence, let's move
it now to be a C struct in order to be able to easily use libosmocore
features there, such as FSMs.
Some helper classes which GprsMs uses are also mostly move to C since
they are mostly structs with methods, so there's no point in having
duplicated APIs for C++ and C for such simple cases.
For some more complex classes, like (ul_,dl_)tbf, C API bindings are
added where needed so that GprsMs can use functionalitites from that
class. Most of those APIs can be kept afterwards and drop the C++ ones
since they provide no benefit in general.
Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c
2020-12-16 14:59:45 +00:00
|
|
|
if (!ms_dl_tbf(ms))
|
2019-09-05 15:13:33 +00:00
|
|
|
continue;
|
|
|
|
bts_data->app_info_pending++;
|
|
|
|
ms->app_info_pending = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bts_data->app_info_pending) {
|
|
|
|
LOGP(DL1IF, LOGL_NOTICE, "Packet Application Information will not be sent, no subscribers with active"
|
|
|
|
" TBF\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bts_data->app_info) {
|
|
|
|
LOGP(DL1IF, LOGL_NOTICE, "Previous Packet Application Information was not sent to all subscribers,"
|
|
|
|
" overwriting with new one\n");
|
|
|
|
msgb_free(bts_data->app_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "Sending Packet Application Information to %i subscribers with active TBF\n",
|
|
|
|
bts_data->app_info_pending);
|
|
|
|
bts_data->app_info = gprs_rlcmac_app_info_msg(app_info_req);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
|
2012-07-06 06:58:22 +00:00
|
|
|
{
|
2012-07-12 10:49:15 +00:00
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
switch (msg_type) {
|
|
|
|
case PCU_IF_MSG_DATA_IND:
|
2017-07-21 19:56:23 +00:00
|
|
|
rc = pcu_rx_data_ind(&pcu_prim->u.data_ind);
|
2012-07-12 10:49:15 +00:00
|
|
|
break;
|
2012-09-27 07:23:24 +00:00
|
|
|
case PCU_IF_MSG_DATA_CNF:
|
|
|
|
rc = pcu_rx_data_cnf(&pcu_prim->u.data_cnf);
|
|
|
|
break;
|
2012-07-12 10:49:15 +00:00
|
|
|
case PCU_IF_MSG_RTS_REQ:
|
|
|
|
rc = pcu_rx_rts_req(&pcu_prim->u.rts_req);
|
|
|
|
break;
|
|
|
|
case PCU_IF_MSG_RACH_IND:
|
|
|
|
rc = pcu_rx_rach_ind(&pcu_prim->u.rach_ind);
|
|
|
|
break;
|
|
|
|
case PCU_IF_MSG_INFO_IND:
|
|
|
|
rc = pcu_rx_info_ind(&pcu_prim->u.info_ind);
|
|
|
|
break;
|
|
|
|
case PCU_IF_MSG_TIME_IND:
|
|
|
|
rc = pcu_rx_time_ind(&pcu_prim->u.time_ind);
|
|
|
|
break;
|
2012-07-19 11:06:26 +00:00
|
|
|
case PCU_IF_MSG_PAG_REQ:
|
|
|
|
rc = pcu_rx_pag_req(&pcu_prim->u.pag_req);
|
|
|
|
break;
|
2017-07-10 22:06:38 +00:00
|
|
|
case PCU_IF_MSG_SUSP_REQ:
|
|
|
|
rc = pcu_rx_susp_req(&pcu_prim->u.susp_req);
|
|
|
|
break;
|
2019-09-05 15:13:33 +00:00
|
|
|
case PCU_IF_MSG_APP_INFO_REQ:
|
|
|
|
rc = pcu_rx_app_info_req(&pcu_prim->u.app_info_req);
|
|
|
|
break;
|
2012-07-12 10:49:15 +00:00
|
|
|
default:
|
2018-10-06 08:42:58 +00:00
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Received unknown PCU msg type %d\n",
|
2012-07-12 10:49:15 +00:00
|
|
|
msg_type);
|
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
2018-04-10 11:12:42 +00:00
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
return rc;
|
2012-07-06 06:58:22 +00:00
|
|
|
}
|