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.
|
|
|
|
*/
|
|
|
|
|
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>
|
2021-02-09 17:47:34 +00:00
|
|
|
#include <osmocom/gsm/gsm48_rest_octets.h>
|
2021-01-25 22:43:52 +00:00
|
|
|
#include <osmocom/gsm/sysinfo.h>
|
2023-01-10 11:49:28 +00:00
|
|
|
#include <osmocom/gsm/gsm0502.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
2021-09-07 12:09:50 +00:00
|
|
|
|
|
|
|
#include <nacc_fsm.h>
|
2023-02-13 12:37:22 +00:00
|
|
|
#include <pcu_l1_if_phy.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>
|
2023-04-17 14:33:35 +00:00
|
|
|
#include <gprs_ms.h>
|
2012-06-23 08:33:16 +00:00
|
|
|
|
2012-07-13 12:00:21 +00:00
|
|
|
extern void *tall_pcu_ctx;
|
|
|
|
|
2023-02-03 15:52:42 +00:00
|
|
|
struct e1_ccu_conn_pars {
|
|
|
|
struct llist_head entry;
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
/*
|
|
|
|
* 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
2021-09-07 12:09:50 +00:00
|
|
|
/* Can be used to allocate message with non-variable size */
|
2012-07-12 10:49:15 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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
2021-09-07 12:09:50 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-03-09 15:19:22 +00:00
|
|
|
static int pcu_tx_act_req(struct gprs_rlcmac_bts *bts, const struct gprs_rlcmac_pdch *pdch,
|
|
|
|
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;
|
|
|
|
|
2021-03-09 15:19:22 +00:00
|
|
|
LOGPDCH(pdch, DL1IF, LOGL_INFO, "Sending %s request\n",
|
|
|
|
(activate) ? "activate" : "deactivate");
|
2012-07-12 10:49:15 +00:00
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
msg = pcu_msgb_alloc(PCU_IF_MSG_ACT_REQ, bts->nr);
|
2012-07-12 10:49:15 +00:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
pcu_prim = (struct gsm_pcu_if *) msg->data;
|
|
|
|
act_req = &pcu_prim->u.act_req;
|
|
|
|
act_req->activate = activate;
|
2021-03-09 15:19:22 +00:00
|
|
|
act_req->trx_nr = pdch->trx_no();
|
|
|
|
act_req->ts_nr = pdch->ts_no;
|
2012-07-12 10:49:15 +00:00
|
|
|
|
|
|
|
return pcu_sock_send(msg);
|
2012-04-12 10:24:35 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_tx_data_req(struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts, uint8_t sapi,
|
2012-07-12 10:49:15 +00:00
|
|
|
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;
|
2021-01-18 16:14:14 +00:00
|
|
|
int current_fn = bts_current_frame_number(bts);
|
2012-07-12 10:49:15 +00:00
|
|
|
|
2021-03-09 15:19:22 +00:00
|
|
|
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));
|
2012-07-12 10:49:15 +00:00
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_REQ, bts->nr);
|
2012-07-12 10:49:15 +00:00
|
|
|
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;
|
2021-09-22 11:56:27 +00:00
|
|
|
if (len)
|
|
|
|
memcpy(data_req->data, data, len);
|
2012-07-12 10:49:15 +00:00
|
|
|
data_req->len = len;
|
|
|
|
|
|
|
|
return pcu_sock_send(msg);
|
2012-03-05 15:24:57 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
void pcu_l1if_tx_pdtch(msgb *msg, struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts, uint16_t arfcn,
|
2012-07-12 10:49:15 +00:00
|
|
|
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
|
2016-02-22 10:42:33 +00:00
|
|
|
if (bts->trx[trx].fl1h) {
|
2021-09-22 11:56:27 +00:00
|
|
|
if (!msg) /* Simply skip sending idle frames to L1 */
|
|
|
|
return;
|
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
|
2021-09-22 11:56:27 +00:00
|
|
|
if (!msg) {
|
|
|
|
pcu_tx_data_req(bts, trx, ts, PCU_IF_SAPI_PDTCH, arfcn, fn, block_nr,
|
|
|
|
NULL, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
pcu_tx_data_req(bts, 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
|
|
|
}
|
|
|
|
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts,
|
|
|
|
uint8_t trx, uint8_t ts, uint16_t arfcn,
|
2019-10-05 15:22:08 +00:00
|
|
|
uint32_t fn, uint8_t block_nr,
|
|
|
|
uint8_t *data, size_t data_len)
|
2012-03-05 15:24:57 +00:00
|
|
|
{
|
2022-09-29 19:21:59 +00:00
|
|
|
if (data_len && the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PTCCH))
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
gsmtap_send(the_pcu->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) {
|
2021-09-22 11:56:27 +00:00
|
|
|
if (!data_len) /* Simply skip sending idle frames to L1 */
|
|
|
|
return;
|
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
|
2021-09-22 11:56:27 +00:00
|
|
|
if (!data_len) {
|
|
|
|
pcu_tx_data_req(bts, trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr, NULL, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
pcu_tx_data_req(bts, trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr, data, data_len);
|
2012-03-18 11:48:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-25 10:58:32 +00:00
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
struct gsm_pcu_if_agch agch = { 0 };
|
|
|
|
|
|
|
|
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, agch.data, GSM_MACBLOCK_LEN);
|
|
|
|
|
|
|
|
pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_AGCH_2, 0, 0, 0, (uint8_t*)&agch, sizeof(agch));
|
|
|
|
}
|
|
|
|
|
2023-05-11 11:38:18 +00:00
|
|
|
/* 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. */
|
2023-08-24 10:45:18 +00:00
|
|
|
void pcu_l1if_tx_pch2(struct gprs_rlcmac_bts *bts, struct bitvec *block, int plen, bool confirm,
|
|
|
|
const char *imsi, uint32_t msg_id)
|
2023-02-01 12:51:56 +00:00
|
|
|
{
|
2023-08-10 11:31:41 +00:00
|
|
|
struct gsm_pcu_if_pch pch = { 0 };
|
2023-02-01 12:51:56 +00:00
|
|
|
|
2023-08-10 11:31:41 +00:00
|
|
|
pch.msg_id = msg_id;
|
2023-03-07 17:19:08 +00:00
|
|
|
if (imsi)
|
2023-08-10 11:31:41 +00:00
|
|
|
OSMO_STRLCPY_ARRAY(pch.imsi, imsi);
|
|
|
|
/* OS#6097: if strlen(pch.imsi) == 0: We assume the MS is in non-DRX
|
2023-07-14 17:22:09 +00:00
|
|
|
* 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).
|
|
|
|
*/
|
2023-02-01 12:51:56 +00:00
|
|
|
|
2023-08-24 10:45:18 +00:00
|
|
|
pch.confirm = confirm;
|
2023-08-10 11:31:41 +00:00
|
|
|
pch.data[0] = (plen << 2) | 0x01;
|
|
|
|
bitvec_pack(block, pch.data + 1);
|
2023-02-01 12:51:56 +00:00
|
|
|
|
2023-07-31 11:05:24 +00:00
|
|
|
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,
|
2023-08-10 11:31:41 +00:00
|
|
|
pch.data, GSM_MACBLOCK_LEN);
|
2023-07-31 11:05:24 +00:00
|
|
|
|
2023-08-10 11:31:41 +00:00
|
|
|
pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_PCH_2, 0, 0, 0, (uint8_t*)&pch, sizeof(pch));
|
2023-02-01 12:51:56 +00:00
|
|
|
}
|
|
|
|
|
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
2021-09-07 12:09:50 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
void pcu_rx_block_time(struct gprs_rlcmac_bts *bts, uint16_t arfcn, uint32_t fn, uint8_t ts_no)
|
2015-08-26 11:22:28 +00:00
|
|
|
{
|
2021-03-17 14:26:37 +00:00
|
|
|
bts_set_current_block_frame_number(bts, fn);
|
2015-08-26 11:22:28 +00:00
|
|
|
}
|
|
|
|
|
2021-03-09 13:50:14 +00:00
|
|
|
int pcu_rx_data_ind_pdtch(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_pdch *pdch, 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
|
|
|
{
|
Add new PDCH UL Controller, drop SBAllocator class
Right now we handle different types of UL allocations in different
classes like PollAllocator and SBAllocator, and they usually don't take
into account the other one in most cases. Furthermore, those objects are
usually per-BTS object, instead of per PDCH object.
This is a first step towards having a unified per-PDCH controller which
takes care of controlling what is scheduled and hence expected on the
uplink. Each PDCH has a UL Controller which keeps track of all reserved
uplink frame, be it SB, RRBP poll or USF assigned, all under the same
API.
As a first step, only the SBA part is fully implemented and used (being
it the easiest part to replace); TBF poll+usf will come in follow-up
patches later on. As a result, the SBAllocator per-BTS class dissappears
but some of its code is refactored/reused to provide more features to the
gprs_rlcmac_sba object, which is also further integrated into the new UL
Controller.
Related: OS#5020
Change-Id: I84b24beea4a1aa2c1528f41435f77bd16df2b947
2021-03-08 13:57:58 +00:00
|
|
|
int rc;
|
|
|
|
|
2023-06-01 13:11:54 +00:00
|
|
|
/* First of all, update TDMA clock: */
|
|
|
|
bts_set_current_frame_number(bts, fn);
|
|
|
|
|
2021-08-31 12:09:42 +00:00
|
|
|
if (!pdch->is_enabled()) {
|
|
|
|
LOGPDCH(pdch, DL1IF, LOGL_INFO, "Received DATA.ind (PDTCH) on disabled TS\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
Add new PDCH UL Controller, drop SBAllocator class
Right now we handle different types of UL allocations in different
classes like PollAllocator and SBAllocator, and they usually don't take
into account the other one in most cases. Furthermore, those objects are
usually per-BTS object, instead of per PDCH object.
This is a first step towards having a unified per-PDCH controller which
takes care of controlling what is scheduled and hence expected on the
uplink. Each PDCH has a UL Controller which keeps track of all reserved
uplink frame, be it SB, RRBP poll or USF assigned, all under the same
API.
As a first step, only the SBA part is fully implemented and used (being
it the easiest part to replace); TBF poll+usf will come in follow-up
patches later on. As a result, the SBAllocator per-BTS class dissappears
but some of its code is refactored/reused to provide more features to the
gprs_rlcmac_sba object, which is also further integrated into the new UL
Controller.
Related: OS#5020
Change-Id: I84b24beea4a1aa2c1528f41435f77bd16df2b947
2021-03-08 13:57:58 +00:00
|
|
|
rc = pdch->rcv_block(data, len, fn, meas);
|
|
|
|
pdch_ulc_expire_fn(pdch->ulc, fn);
|
|
|
|
return rc;
|
2012-12-18 09:47:28 +00:00
|
|
|
}
|
|
|
|
|
2021-06-08 16:53:40 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_data_ind_bcch(struct gprs_rlcmac_bts *bts, uint8_t *data, uint8_t len)
|
2017-09-01 09:02:40 +00:00
|
|
|
{
|
2021-06-08 16:53:40 +00:00
|
|
|
struct gsm48_system_information_type_2 *si2;
|
2021-02-09 17:47:34 +00:00
|
|
|
const uint8_t *si_ro;
|
2021-06-08 16:53:40 +00:00
|
|
|
|
2021-01-25 22:43:52 +00:00
|
|
|
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");
|
2017-09-01 09:02:40 +00:00
|
|
|
bts->si13_is_set = false;
|
|
|
|
|
2021-01-25 22:43:52 +00:00
|
|
|
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;
|
2021-06-08 16:53:40 +00:00
|
|
|
case SYSINFO_TYPE_2:
|
|
|
|
bts->si2_is_set = false;
|
|
|
|
break;
|
2021-01-25 22:43:52 +00:00
|
|
|
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;
|
2021-06-08 16:53:40 +00:00
|
|
|
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;
|
2021-01-25 22:43:52 +00:00
|
|
|
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;
|
2021-02-09 17:47:34 +00:00
|
|
|
si_ro = ((struct gsm48_system_information_type_13*)data)->rest_octets;
|
2021-06-01 14:43:41 +00:00
|
|
|
if (osmo_gsm48_rest_octets_si13_decode(&bts->si13_ro_decoded, si_ro) < 0)
|
2021-02-09 17:47:34 +00:00
|
|
|
LOGP(DPCU, LOGL_ERROR, "Error decoding SI13\n");
|
2023-06-19 11:58:45 +00:00
|
|
|
/* Update our cached timers from it: */
|
2023-06-12 11:44:55 +00:00
|
|
|
osmo_tdef_set(bts->T_defs_bts, 3168, bts->si13_ro_decoded.cell_opts.t3168, OSMO_TDEF_MS);
|
2023-06-19 11:58:45 +00:00
|
|
|
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");
|
2021-01-25 22:43:52 +00:00
|
|
|
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);
|
2017-09-01 09:02:40 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_data_ind(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_data *data_ind)
|
2012-03-18 11:48:51 +00:00
|
|
|
{
|
2016-02-22 10:42:33 +00:00
|
|
|
int rc;
|
2021-01-18 16:14:14 +00:00
|
|
|
int current_fn = bts_current_frame_number(bts);
|
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};
|
2021-03-09 13:50:14 +00:00
|
|
|
struct gprs_rlcmac_pdch *pdch;
|
2020-06-30 15:57:42 +00:00
|
|
|
uint8_t gsmtap_chantype;
|
2017-09-01 09:00:39 +00:00
|
|
|
|
2021-03-09 13:50:14 +00:00
|
|
|
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));
|
2012-07-12 10:49:15 +00:00
|
|
|
|
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:
|
2021-03-09 13:50:14 +00:00
|
|
|
pdch = &bts->trx[data_ind->trx_nr].pdch[data_ind->ts_nr];
|
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
|
|
|
|
2021-03-09 13:50:14 +00:00
|
|
|
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);
|
2019-07-09 09:16:35 +00:00
|
|
|
|
2021-03-09 13:50:14 +00:00
|
|
|
rc = pcu_rx_data_ind_pdtch(bts, pdch, data_ind->data, data_ind->len,
|
|
|
|
data_ind->fn, &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:
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_data_ind_bcch(bts, 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:
|
2021-03-09 13:50:14 +00:00
|
|
|
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);
|
2012-07-12 10:49:15 +00:00
|
|
|
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
|
|
|
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
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,
|
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;
|
|
|
|
}
|
|
|
|
|
2023-08-10 11:31:41 +00:00
|
|
|
static int pcu_rx_data_cnf2(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_data_cnf *data_cnf)
|
2023-02-01 15:10:52 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
2023-08-10 11:31:41 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Data confirm received: sapi=%d\n", data_cnf->sapi);
|
2023-02-01 15:10:52 +00:00
|
|
|
|
2023-08-10 11:31:41 +00:00
|
|
|
switch (data_cnf->sapi) {
|
|
|
|
case PCU_IF_SAPI_PCH_2:
|
2023-08-25 10:58:32 +00:00
|
|
|
case PCU_IF_SAPI_AGCH_2:
|
2023-08-10 11:31:41 +00:00
|
|
|
bts_rcv_imm_ass_cnf(bts, NULL, data_cnf->msg_id);
|
2023-02-01 15:10:52 +00:00
|
|
|
break;
|
|
|
|
default:
|
2023-08-10 11:31:41 +00:00
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Received PCU data confirm with unsupported sapi %d\n", data_cnf->sapi);
|
2023-02-01 15:10:52 +00:00
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-12-18 09:47:28 +00:00
|
|
|
// FIXME: remove this, when changed from c++ to c.
|
2021-01-18 16:14:14 +00:00
|
|
|
int pcu_rx_rts_req_pdtch(struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts,
|
2012-12-18 09:47:28 +00:00
|
|
|
uint32_t fn, uint8_t block_nr)
|
|
|
|
{
|
2021-01-18 16:14:14 +00:00
|
|
|
return gprs_rlcmac_rcv_rts_block(bts,
|
2016-07-20 11:05:05 +00:00
|
|
|
trx, ts, fn, block_nr);
|
2012-12-18 09:47:28 +00:00
|
|
|
}
|
2021-01-18 16:14:14 +00:00
|
|
|
int pcu_rx_rts_req_ptcch(struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts,
|
2019-10-05 15:22:08 +00:00
|
|
|
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];
|
2022-04-01 16:27:04 +00:00
|
|
|
if (!pdch_is_enabled(pdch))
|
2019-10-05 15:22:08 +00:00
|
|
|
return -EAGAIN;
|
|
|
|
|
2021-09-20 09:20:09 +00:00
|
|
|
/* If there's no TBF attached to this PDCH, we can skip Tx of PTCCH
|
|
|
|
* since there's nothing worthy of being transmitted. This way BTS can
|
|
|
|
* identify idle blocks and send nothing or dumy blocks with reduced
|
|
|
|
* energy for the sake of energy saving.
|
|
|
|
*/
|
|
|
|
const unsigned num_tbfs = pdch->num_tbfs(GPRS_RLCMAC_DL_TBF)
|
|
|
|
+ pdch->num_tbfs(GPRS_RLCMAC_UL_TBF);
|
|
|
|
bool skip_idle = (num_tbfs == 0);
|
2023-11-22 16:16:19 +00:00
|
|
|
|
2023-12-05 13:04:52 +00:00
|
|
|
if (bts->gen_idle_blocks_C0)
|
2021-09-20 09:20:09 +00:00
|
|
|
skip_idle = skip_idle && trx != 0;
|
2023-11-22 16:16:19 +00:00
|
|
|
|
2021-09-22 11:56:27 +00:00
|
|
|
if (skip_idle) {
|
|
|
|
pcu_l1if_tx_ptcch(bts, trx, ts, bts->trx[trx].arfcn, fn, block_nr,
|
|
|
|
NULL, 0);
|
2021-09-20 09:20:09 +00:00
|
|
|
return 0;
|
2021-09-22 11:56:27 +00:00
|
|
|
}
|
2021-09-20 09:20:09 +00:00
|
|
|
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
pcu_l1if_tx_ptcch(bts, trx, ts, bts->trx[trx].arfcn, fn, block_nr,
|
2019-10-05 15:22:08 +00:00
|
|
|
pdch->ptcch_msg, GSM_MACBLOCK_LEN);
|
|
|
|
return 0;
|
|
|
|
}
|
2012-12-18 09:47:28 +00:00
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_rts_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_rts_req *rts_req)
|
2012-04-17 18:00:31 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
2021-01-18 16:14:14 +00:00
|
|
|
int current_fn = bts_current_frame_number(bts);
|
2021-03-09 15:19:22 +00:00
|
|
|
const struct gprs_rlcmac_pdch *pdch;
|
|
|
|
pdch = &bts->trx[rts_req->trx_nr].pdch[rts_req->ts_nr];
|
2012-04-17 18:00:31 +00:00
|
|
|
|
2021-03-09 15:19:22 +00:00
|
|
|
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);
|
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:
|
2021-01-18 16:14:14 +00:00
|
|
|
pcu_rx_rts_req_pdtch(bts, 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:
|
2021-01-18 16:14:14 +00:00
|
|
|
pcu_rx_rts_req_ptcch(bts, rts_req->trx_nr, rts_req->ts_nr,
|
2019-10-05 15:22:08 +00:00
|
|
|
rts_req->fn, rts_req->block_nr);
|
2012-03-18 11:48:51 +00:00
|
|
|
break;
|
|
|
|
default:
|
2021-03-09 15:19:22 +00:00
|
|
|
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);
|
2012-07-12 10:49:15 +00:00
|
|
|
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
|
|
|
|
2023-02-27 14:11:29 +00:00
|
|
|
/* C -> C++ adapter for direct PHY access code (e.g. osmo-bts-sysmo) */
|
2021-01-18 16:14:14 +00:00
|
|
|
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)
|
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,
|
2023-05-31 17:10:51 +00:00
|
|
|
.rfn = fn2rfn(fn),
|
2023-05-31 18:03:41 +00:00
|
|
|
.fn = fn,
|
2020-05-21 12:55:46 +00:00
|
|
|
.qta = qta,
|
|
|
|
};
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
return bts_rcv_ptcch_rach(bts, &rip);
|
2019-10-05 16:45:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_rach_ind(struct gprs_rlcmac_bts *bts, 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;
|
2023-05-31 17:10:51 +00:00
|
|
|
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);
|
2012-06-23 08:33:16 +00:00
|
|
|
|
2023-05-31 17:10:51 +00:00
|
|
|
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);
|
2012-06-23 08:33:16 +00:00
|
|
|
|
2023-01-10 11:49:28 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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,
|
2023-05-31 17:10:51 +00:00
|
|
|
.rfn = rfn,
|
2023-05-31 18:03:41 +00:00
|
|
|
.fn = bts_rfn_to_fn(bts, rfn),
|
2020-05-21 12:55:46 +00:00
|
|
|
.qta = rach_ind->qta,
|
|
|
|
};
|
|
|
|
|
2012-07-12 10:49:15 +00:00
|
|
|
switch (rach_ind->sapi) {
|
|
|
|
case PCU_IF_SAPI_RACH:
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = bts_rcv_rach(bts, &rip);
|
2012-07-12 10:49:15 +00:00
|
|
|
break;
|
2019-10-05 16:45:31 +00:00
|
|
|
case PCU_IF_SAPI_PTCCH:
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = bts_rcv_ptcch_rach(bts, &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;
|
|
|
|
}
|
|
|
|
|
2021-02-16 15:57:15 +00:00
|
|
|
return gprs_ns_update_config(bts, info_ind->nsei, local, remote, nsvci, valid);
|
2020-10-12 00:27:22 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 09:44:31 +00:00
|
|
|
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 }
|
|
|
|
};
|
|
|
|
|
2023-11-22 16:16:19 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_info_ind(struct gprs_rlcmac_bts *bts, const struct gsm_pcu_if_info_ind *info_ind)
|
2012-06-23 08:33:16 +00:00
|
|
|
{
|
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
|
|
|
|
2023-03-03 10:39:00 +00:00
|
|
|
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");
|
|
|
|
|
2023-02-01 12:51:56 +00:00
|
|
|
LOGP(DL1IF, LOGL_DEBUG, "Info indication received:\n");
|
|
|
|
|
2023-10-10 11:59:38 +00:00
|
|
|
if (info_ind->version != PCU_IF_VERSION) {
|
2023-02-01 12:51:56 +00:00
|
|
|
fprintf(stderr, "PCU interface version number of BTS/BSC (%u) is different (%u).\nPlease use a BTS/BSC with a compatble interface!\n",
|
2012-07-18 08:06:48 +00:00
|
|
|
info_ind->version, PCU_IF_VERSION);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2023-02-01 12:51:56 +00:00
|
|
|
the_pcu->pcu_if_version = info_ind->version;
|
2012-07-12 10:49:15 +00:00
|
|
|
|
|
|
|
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++)
|
2022-03-30 20:09:06 +00:00
|
|
|
if (bts->trx[trx_nr].pdch[ts_nr].is_enabled())
|
|
|
|
bts->trx[trx_nr].pdch[ts_nr].disable();
|
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);
|
2021-01-20 12:48:31 +00:00
|
|
|
bts->cgi_ps.rai.lac.plmn.mcc = info_ind->mcc;
|
|
|
|
bts->cgi_ps.rai.lac.plmn.mnc = info_ind->mnc;
|
|
|
|
bts->cgi_ps.rai.lac.plmn.mnc_3_digits = info_ind->mnc_3_digits;
|
|
|
|
bts->cgi_ps.rai.lac.lac = info_ind->lac;
|
|
|
|
bts->cgi_ps.rai.rac = info_ind->rac;
|
|
|
|
bts->cgi_ps.cell_identity = info_ind->cell_id;
|
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
|
|
|
}
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
bts_recalc_max_cs(bts);
|
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
|
|
|
}
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
bts_recalc_max_mcs(bts);
|
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,
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
the_pcu->vty.force_initial_cs ? " (VTY forced, ignoring)" : "");
|
2021-01-14 15:20:57 +00:00
|
|
|
bts->pcuif_info_ind.initial_cs = info_ind->initial_cs;
|
|
|
|
bts_recalc_initial_cs(bts);
|
2020-11-03 14:59:39 +00:00
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_DEBUG, " initial_mcs=%u%s\n", info_ind->initial_mcs,
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
the_pcu->vty.force_initial_mcs ? " (VTY forced, ignoring)" : "");
|
2021-01-14 15:20:57 +00:00
|
|
|
bts->pcuif_info_ind.initial_mcs = info_ind->initial_mcs;
|
|
|
|
bts_recalc_initial_mcs(bts);
|
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;
|
2023-09-29 12:36:35 +00:00
|
|
|
if ((info_ind->flags & PCU_IF_FLAG_DIRECT_PHY)
|
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)
|
2023-04-25 07:41:17 +00:00
|
|
|
bts->trx[trx_nr].fl1h = l1if_open_trx(
|
2023-03-03 10:39:00 +00:00
|
|
|
bts->nr, trx_nr,
|
2020-07-23 18:24:47 +00:00
|
|
|
info_ind->trx[trx_nr].hlayer1,
|
Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.
This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.
This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.
The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.
Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-13 17:54:38 +00:00
|
|
|
the_pcu->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 "
|
2023-02-27 14:11:29 +00:00
|
|
|
"PHY access for PDCH.\n");
|
2012-12-18 09:47:28 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
#else
|
2023-02-27 14:11:29 +00:00
|
|
|
LOGP(DL1IF, LOGL_FATAL, "Compiled without direct PHY "
|
2012-12-18 09:47:28 +00:00
|
|
|
"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++) {
|
2022-10-27 13:25:31 +00:00
|
|
|
const struct gsm_pcu_if_info_trx_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 &
|
2023-09-29 12:36:35 +00:00
|
|
|
PCU_IF_FLAG_DIRECT_PHY))
|
2012-12-18 09:47:28 +00:00
|
|
|
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
|
2021-03-09 15:19:22 +00:00
|
|
|
pcu_tx_act_req(bts, pdch, 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 */
|
2022-10-27 13:07:57 +00:00
|
|
|
if (its->hopping) {
|
2020-07-20 17:54:42 +00:00
|
|
|
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()) {
|
2023-02-27 14:32:00 +00:00
|
|
|
#ifdef ENABLE_DIRECT_PHY
|
2023-09-29 12:36:35 +00:00
|
|
|
if ((info_ind->flags & PCU_IF_FLAG_DIRECT_PHY))
|
2023-02-27 14:32:00 +00:00
|
|
|
l1if_disconnect_pdch(bts->trx[trx_nr].fl1h, ts_nr);
|
|
|
|
#endif
|
2021-03-09 15:19:22 +00:00
|
|
|
pcu_tx_act_req(bts, pdch, 0);
|
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
|
|
|
|
2023-10-05 09:44:31 +00:00
|
|
|
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;
|
2023-12-05 13:04:52 +00:00
|
|
|
bts->gen_idle_blocks_C0 = decide_gen_idle_blocks(bts);
|
2023-10-05 09:44:31 +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
|
|
|
}
|
|
|
|
|
2023-02-03 15:52:42 +00:00
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_time_ind(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_time_ind *time_ind)
|
2012-06-23 08:33:16 +00:00
|
|
|
{
|
2012-07-12 10:49:15 +00:00
|
|
|
/* omit frame numbers not starting at a MAC block */
|
2023-06-01 08:54:17 +00:00
|
|
|
if (!fn_valid(time_ind->fn))
|
2012-07-12 10:49:15 +00:00
|
|
|
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
|
|
|
|
2021-03-05 17:59:05 +00:00
|
|
|
/* Ignore TIME.ind completely, we nowadays relay on DATA.ind always
|
|
|
|
* providing all block FNs. */
|
2012-06-23 08:33:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_pag_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_pag_req *pag_req)
|
2012-07-19 11:06:26 +00:00
|
|
|
{
|
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;
|
Optimize PAGING-CS PDCH set selection when target MS is known
Before this patch, when a PAGING-GS was received in PCU from SGSN, it
would always forward the paging request to all PDCHs in all TRXs of all
BTS (well, it did some heuristics to avoid sending it in some PDCHs
where onyl repeated TBFs would be listening).
The previous behavior, didn't make much sense in the case where the PCU
is asked to page an MS which it knows (ie in which PDCHs is listening
to). Hence, in that case it makes sense to simply send the paging
request on 1 PDCH where the MS is listening, instead of sending it in a
big set of different PDCHs.
This commit also splits the old get_paging_mi() helper which was
erroneously created to parseboth CS/PS-PAGING requesst, since they
actually use a different set of target subscriber information (for
instance, CS-PAGING provides optionally a TLLI, and one provides P-TMSI
while the other provides TMSI).
In this patch, the handling of CS paging request is split into 2 parts:
1- A new helper "struct paging_req_cs" is introduced, where incoming
CS-PAGING requests (from both SGSN over BSSGP and BTS/BSC over PCUIF)
are parsed and information stored. Then, from available information, it
tries to find a target MS if avaialable
2- bts_add_paging() is called from both BSSGP and PCUIF paths with the
helper struct and the target MS (NULL if not found). If MS exists,
paging is forwarding only on 1 PDCH that MS is attached to. If no MS
exists, then the old heursitics are used to forward the request to all
MS.
Change-Id: Iea46d5321a29d800813b1aa2bf4ce175ce45e2cf
2021-05-13 15:44:51 +00:00
|
|
|
struct GprsMs *ms = NULL;
|
|
|
|
struct paging_req_cs req = { .chan_needed = pag_req->chan_needed,
|
|
|
|
.tlli = GSM_RESERVED_TMSI };
|
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
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Optimize PAGING-CS PDCH set selection when target MS is known
Before this patch, when a PAGING-GS was received in PCU from SGSN, it
would always forward the paging request to all PDCHs in all TRXs of all
BTS (well, it did some heuristics to avoid sending it in some PDCHs
where onyl repeated TBFs would be listening).
The previous behavior, didn't make much sense in the case where the PCU
is asked to page an MS which it knows (ie in which PDCHs is listening
to). Hence, in that case it makes sense to simply send the paging
request on 1 PDCH where the MS is listening, instead of sending it in a
big set of different PDCHs.
This commit also splits the old get_paging_mi() helper which was
erroneously created to parseboth CS/PS-PAGING requesst, since they
actually use a different set of target subscriber information (for
instance, CS-PAGING provides optionally a TLLI, and one provides P-TMSI
while the other provides TMSI).
In this patch, the handling of CS paging request is split into 2 parts:
1- A new helper "struct paging_req_cs" is introduced, where incoming
CS-PAGING requests (from both SGSN over BSSGP and BTS/BSC over PCUIF)
are parsed and information stored. Then, from available information, it
tries to find a target MS if avaialable
2- bts_add_paging() is called from both BSSGP and PCUIF paths with the
helper struct and the target MS (NULL if not found). If MS exists,
paging is forwarding only on 1 PDCH that MS is attached to. If no MS
exists, then the old heursitics are used to forward the request to all
MS.
Change-Id: Iea46d5321a29d800813b1aa2bf4ce175ce45e2cf
2021-05-13 15:44:51 +00:00
|
|
|
switch (mi.type) {
|
|
|
|
case GSM_MI_TYPE_TMSI:
|
|
|
|
req.mi_tmsi = mi;
|
|
|
|
req.mi_tmsi_present = true;
|
|
|
|
/* TODO: look up MS by TMSI? Derive TLLI? */
|
|
|
|
break;
|
|
|
|
case GSM_MI_TYPE_IMSI:
|
|
|
|
req.mi_imsi = mi;
|
|
|
|
req.mi_imsi_present = true;
|
2023-04-17 16:16:48 +00:00
|
|
|
ms = bts_get_ms_by_imsi(bts, req.mi_imsi.imsi);
|
Optimize PAGING-CS PDCH set selection when target MS is known
Before this patch, when a PAGING-GS was received in PCU from SGSN, it
would always forward the paging request to all PDCHs in all TRXs of all
BTS (well, it did some heuristics to avoid sending it in some PDCHs
where onyl repeated TBFs would be listening).
The previous behavior, didn't make much sense in the case where the PCU
is asked to page an MS which it knows (ie in which PDCHs is listening
to). Hence, in that case it makes sense to simply send the paging
request on 1 PDCH where the MS is listening, instead of sending it in a
big set of different PDCHs.
This commit also splits the old get_paging_mi() helper which was
erroneously created to parseboth CS/PS-PAGING requesst, since they
actually use a different set of target subscriber information (for
instance, CS-PAGING provides optionally a TLLI, and one provides P-TMSI
while the other provides TMSI).
In this patch, the handling of CS paging request is split into 2 parts:
1- A new helper "struct paging_req_cs" is introduced, where incoming
CS-PAGING requests (from both SGSN over BSSGP and BTS/BSC over PCUIF)
are parsed and information stored. Then, from available information, it
tries to find a target MS if avaialable
2- bts_add_paging() is called from both BSSGP and PCUIF paths with the
helper struct and the target MS (NULL if not found). If MS exists,
paging is forwarding only on 1 PDCH that MS is attached to. If no MS
exists, then the old heursitics are used to forward the request to all
MS.
Change-Id: Iea46d5321a29d800813b1aa2bf4ce175ce45e2cf
2021-05-13 15:44:51 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Unexpected MI type %u\n", mi.type);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bts_add_paging(bts, &req, ms);
|
2012-07-19 11:06:26 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_susp_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_susp_req *susp_req)
|
2017-07-10 22:06:38 +00:00
|
|
|
{
|
2021-01-25 22:43:52 +00:00
|
|
|
struct bssgp_bvc_ctx *bctx = the_pcu->bssgp.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));
|
|
|
|
|
2023-04-17 14:33:35 +00:00
|
|
|
if ((ms = bts_get_ms_by_tlli(bts, susp_req->tlli, GSM_RESERVED_TMSI))) {
|
2020-09-22 13:57:37 +00:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:14:14 +00:00
|
|
|
static int pcu_rx_app_info_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_app_info_req *app_info_req)
|
2019-09-05 15:13:33 +00:00
|
|
|
{
|
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);
|
|
|
|
|
2021-01-18 11:53:54 +00:00
|
|
|
bts->app_info_pending = 0;
|
2023-04-17 14:33:35 +00:00
|
|
|
llist_for_each(tmp, &bts->ms_list) {
|
|
|
|
struct 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;
|
2021-01-18 11:53:54 +00:00
|
|
|
bts->app_info_pending++;
|
2019-09-05 15:13:33 +00:00
|
|
|
ms->app_info_pending = true;
|
|
|
|
}
|
|
|
|
|
2021-01-18 11:53:54 +00:00
|
|
|
if (!bts->app_info_pending) {
|
2019-09-05 15:13:33 +00:00
|
|
|
LOGP(DL1IF, LOGL_NOTICE, "Packet Application Information will not be sent, no subscribers with active"
|
|
|
|
" TBF\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-01-18 11:53:54 +00:00
|
|
|
if (bts->app_info) {
|
2019-09-05 15:13:33 +00:00
|
|
|
LOGP(DL1IF, LOGL_NOTICE, "Previous Packet Application Information was not sent to all subscribers,"
|
|
|
|
" overwriting with new one\n");
|
2021-01-18 11:53:54 +00:00
|
|
|
msgb_free(bts->app_info);
|
2019-09-05 15:13:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "Sending Packet Application Information to %i subscribers with active TBF\n",
|
2021-01-18 11:53:54 +00:00
|
|
|
bts->app_info_pending);
|
|
|
|
bts->app_info = gprs_rlcmac_app_info_msg(app_info_req);
|
2019-09-05 15:13:33 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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
2021-09-07 12:09:50 +00:00
|
|
|
static int pcu_rx_neigh_addr_cnf(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_neigh_addr_cnf *naddr_cnf)
|
|
|
|
{
|
|
|
|
struct llist_head *tmp;
|
|
|
|
struct osmo_cell_global_id_ps cgi_ps;
|
|
|
|
struct osmo_cell_global_id_ps *cgi_ps_ptr = &cgi_ps;
|
|
|
|
|
|
|
|
struct neigh_cache_entry_key neigh_key = {
|
|
|
|
.local_lac = osmo_load16be(&naddr_cnf->orig_req.local_lac),
|
|
|
|
.local_ci = osmo_load16be(&naddr_cnf->orig_req.local_ci),
|
|
|
|
.tgt_arfcn = osmo_load16be(&naddr_cnf->orig_req.tgt_arfcn),
|
|
|
|
.tgt_bsic = naddr_cnf->orig_req.tgt_bsic,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (naddr_cnf->err_code == 0) {
|
|
|
|
cgi_ps.rai.lac.plmn.mcc = osmo_load16be(&naddr_cnf->cgi_ps.mcc);
|
|
|
|
cgi_ps.rai.lac.plmn.mnc = osmo_load16be(&naddr_cnf->cgi_ps.mnc);
|
|
|
|
cgi_ps.rai.lac.plmn.mnc_3_digits = naddr_cnf->cgi_ps.mnc_3_digits;
|
|
|
|
cgi_ps.rai.lac.lac = osmo_load16be(&naddr_cnf->cgi_ps.lac);
|
|
|
|
cgi_ps.rai.rac = naddr_cnf->cgi_ps.rac;
|
|
|
|
cgi_ps.cell_identity = osmo_load16be(&naddr_cnf->cgi_ps.cell_identity);
|
|
|
|
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "Rx Neighbor Address Resolution Confirmation for " NEIGH_CACHE_ENTRY_KEY_FMT ": %s\n",
|
|
|
|
NEIGH_CACHE_ENTRY_KEY_ARGS(&neigh_key), osmo_cgi_ps_name(&cgi_ps));
|
|
|
|
|
|
|
|
/* Cache the cgi_ps so we can avoid requesting again same resolution for a while */
|
|
|
|
neigh_cache_add(bts->pcu->neigh_cache, &neigh_key, &cgi_ps);
|
|
|
|
} else {
|
|
|
|
cgi_ps_ptr = NULL;
|
|
|
|
LOGP(DL1IF, LOGL_INFO, "Rx Neighbor Address Resolution Confirmation for " NEIGH_CACHE_ENTRY_KEY_FMT ": failed with err_code=%u\n",
|
|
|
|
NEIGH_CACHE_ENTRY_KEY_ARGS(&neigh_key), naddr_cnf->err_code);
|
|
|
|
}
|
|
|
|
|
2023-04-17 14:33:35 +00:00
|
|
|
llist_for_each(tmp, &bts->ms_list) {
|
|
|
|
struct GprsMs *ms = llist_entry(tmp, typeof(*ms), list);
|
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
2021-09-07 12:09:50 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-23 17:46:07 +00:00
|
|
|
static int pcu_rx_container(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_container *container)
|
|
|
|
{
|
|
|
|
int rc;
|
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
2021-09-07 12:09:50 +00:00
|
|
|
uint16_t data_length = osmo_load16be(&container->length);
|
2021-06-23 17:46:07 +00:00
|
|
|
|
|
|
|
switch (container->msg_type) {
|
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
2021-09-07 12:09:50 +00:00
|
|
|
case PCU_IF_MSG_NEIGH_ADDR_CNF:
|
|
|
|
if (data_length < sizeof(struct gsm_pcu_if_neigh_addr_cnf)) {
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Rx container(NEIGH_ADDR_CNF) message too short: %u vs exp %zu\n",
|
|
|
|
data_length, sizeof(struct gsm_pcu_if_neigh_addr_cnf));
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
rc = pcu_rx_neigh_addr_cnf(bts, (struct gsm_pcu_if_neigh_addr_cnf*)&container->data);
|
|
|
|
break;
|
2021-06-23 17:46:07 +00:00
|
|
|
default:
|
|
|
|
LOGP(DL1IF, LOGL_NOTICE, "(bts=%d) Rx unexpected msg type (%u) inside container!\n",
|
|
|
|
bts->nr, container->msg_type);
|
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CHECK_IF_MSG_SIZE(prim_len, prim_msg) \
|
|
|
|
do { \
|
|
|
|
size_t _len = PCUIF_HDR_SIZE + sizeof(prim_msg); \
|
|
|
|
if (prim_len < _len) { \
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Received %zu bytes on PCU Socket, but primitive %s " \
|
|
|
|
"size is %zu, discarding\n", prim_len, #prim_msg, _len); \
|
|
|
|
return -EINVAL; \
|
|
|
|
} \
|
|
|
|
} while(0);
|
|
|
|
int pcu_rx(struct gsm_pcu_if *pcu_prim, size_t pcu_prim_length)
|
2012-07-06 06:58:22 +00:00
|
|
|
{
|
2012-07-12 10:49:15 +00:00
|
|
|
int rc = 0;
|
2021-06-23 17:46:07 +00:00
|
|
|
size_t exp_len;
|
2021-01-18 16:14:14 +00:00
|
|
|
struct gprs_rlcmac_bts *bts = gprs_pcu_get_bts_by_nr(the_pcu, pcu_prim->bts_nr);
|
|
|
|
if (!bts) {
|
|
|
|
LOGP(DL1IF, LOGL_NOTICE, "Received message for new BTS%d\n", pcu_prim->bts_nr);
|
|
|
|
bts = bts_alloc(the_pcu, pcu_prim->bts_nr);
|
|
|
|
if (!bts) {
|
|
|
|
LOGP(DL1IF, LOGL_ERROR, "Failed to create object for BTS%d!\n", pcu_prim->bts_nr);
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
}
|
2012-07-12 10:49:15 +00:00
|
|
|
|
2021-06-23 17:46:07 +00:00
|
|
|
switch (pcu_prim->msg_type) {
|
2012-07-12 10:49:15 +00:00
|
|
|
case PCU_IF_MSG_DATA_IND:
|
2021-06-23 17:46:07 +00:00
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.data_ind);
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_data_ind(bts, &pcu_prim->u.data_ind);
|
2012-07-12 10:49:15 +00:00
|
|
|
break;
|
2023-08-10 11:31:41 +00:00
|
|
|
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);
|
2023-02-01 15:10:52 +00:00
|
|
|
break;
|
2012-07-12 10:49:15 +00:00
|
|
|
case PCU_IF_MSG_RTS_REQ:
|
2021-06-23 17:46:07 +00:00
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.rts_req);
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_rts_req(bts, &pcu_prim->u.rts_req);
|
2012-07-12 10:49:15 +00:00
|
|
|
break;
|
|
|
|
case PCU_IF_MSG_RACH_IND:
|
2021-06-23 17:46:07 +00:00
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.rach_ind);
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_rach_ind(bts, &pcu_prim->u.rach_ind);
|
2012-07-12 10:49:15 +00:00
|
|
|
break;
|
|
|
|
case PCU_IF_MSG_INFO_IND:
|
2021-06-23 17:46:07 +00:00
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.info_ind);
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_info_ind(bts, &pcu_prim->u.info_ind);
|
2012-07-12 10:49:15 +00:00
|
|
|
break;
|
2023-02-03 15:52:42 +00:00
|
|
|
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;
|
2012-07-12 10:49:15 +00:00
|
|
|
case PCU_IF_MSG_TIME_IND:
|
2021-06-23 17:46:07 +00:00
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.time_ind);
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_time_ind(bts, &pcu_prim->u.time_ind);
|
2012-07-12 10:49:15 +00:00
|
|
|
break;
|
2012-07-19 11:06:26 +00:00
|
|
|
case PCU_IF_MSG_PAG_REQ:
|
2021-06-23 17:46:07 +00:00
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.pag_req);
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_pag_req(bts, &pcu_prim->u.pag_req);
|
2012-07-19 11:06:26 +00:00
|
|
|
break;
|
2017-07-10 22:06:38 +00:00
|
|
|
case PCU_IF_MSG_SUSP_REQ:
|
2021-06-23 17:46:07 +00:00
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.susp_req);
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_susp_req(bts, &pcu_prim->u.susp_req);
|
2017-07-10 22:06:38 +00:00
|
|
|
break;
|
2019-09-05 15:13:33 +00:00
|
|
|
case PCU_IF_MSG_APP_INFO_REQ:
|
2021-06-23 17:46:07 +00:00
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.app_info_req);
|
2021-01-18 16:14:14 +00:00
|
|
|
rc = pcu_rx_app_info_req(bts, &pcu_prim->u.app_info_req);
|
2019-09-05 15:13:33 +00:00
|
|
|
break;
|
2021-06-20 19:05:24 +00:00
|
|
|
case PCU_IF_MSG_INTERF_IND:
|
|
|
|
/* TODO: handle interference reports */
|
|
|
|
break;
|
2021-06-23 17:46:07 +00:00
|
|
|
case PCU_IF_MSG_CONTAINER:
|
|
|
|
CHECK_IF_MSG_SIZE(pcu_prim_length, pcu_prim->u.container);
|
|
|
|
/* ^ check if we can access container fields, v check with container data length */
|
|
|
|
exp_len = PCUIF_HDR_SIZE + sizeof(pcu_prim->u.container) + osmo_load16be(&pcu_prim->u.container.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);
|
2023-03-26 21:23:54 +00:00
|
|
|
rc = -EINVAL;
|
|
|
|
break;
|
2021-06-23 17:46:07 +00:00
|
|
|
}
|
|
|
|
rc = pcu_rx_container(bts, &pcu_prim->u.container);
|
|
|
|
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",
|
2021-06-23 17:46:07 +00:00
|
|
|
pcu_prim->msg_type);
|
2012-07-12 10:49:15 +00:00
|
|
|
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
|
|
|
}
|