2018-02-19 16:17:28 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2013 by Holger Hans Peter Freyther
|
|
|
|
* Copyright (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
|
|
|
*
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <bts.h>
|
|
|
|
#include <pdch.h>
|
|
|
|
#include <decoding.h>
|
|
|
|
#include <encoding.h>
|
|
|
|
#include <gprs_rlcmac.h>
|
|
|
|
#include <gprs_debug.h>
|
2020-05-18 09:35:35 +00:00
|
|
|
#include <coding_scheme.h>
|
2018-02-19 16:17:28 +00:00
|
|
|
#include <gprs_ms.h>
|
|
|
|
#include <gprs_ms_storage.h>
|
|
|
|
#include <pcu_l1_if.h>
|
|
|
|
#include <rlc.h>
|
|
|
|
#include <sba.h>
|
|
|
|
#include <tbf.h>
|
2019-09-25 15:47:02 +00:00
|
|
|
#include <tbf_ul.h>
|
2018-02-19 16:17:28 +00:00
|
|
|
#include <cxx_linuxlist.h>
|
|
|
|
|
|
|
|
extern "C" {
|
2020-03-26 14:06:11 +00:00
|
|
|
#include <osmocom/core/talloc.h>
|
|
|
|
#include <osmocom/core/msgb.h>
|
2020-03-26 08:45:21 +00:00
|
|
|
#include <osmocom/gsm/gsm48.h>
|
2020-03-26 14:06:11 +00:00
|
|
|
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
|
|
|
#include <osmocom/core/bitvec.h>
|
|
|
|
#include <osmocom/core/gsmtap.h>
|
|
|
|
#include <osmocom/core/logging.h>
|
|
|
|
#include <osmocom/core/utils.h>
|
2020-03-26 14:14:01 +00:00
|
|
|
|
2020-03-26 14:06:11 +00:00
|
|
|
#include "coding_scheme.h"
|
2020-03-26 14:14:01 +00:00
|
|
|
#include "gsm_rlcmac.h"
|
2021-02-01 13:52:48 +00:00
|
|
|
#include "nacc_fsm.h"
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#include <errno.h>
|
2019-10-05 14:57:14 +00:00
|
|
|
#include <stdlib.h>
|
2018-02-19 16:17:28 +00:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
extern void *tall_pcu_ctx;
|
|
|
|
|
|
|
|
static void get_rx_qual_meas(struct pcu_l1_meas *meas, uint8_t rx_qual_enc)
|
|
|
|
{
|
|
|
|
static const int16_t rx_qual_map[] = {
|
|
|
|
0, /* 0,14 % */
|
|
|
|
0, /* 0,28 % */
|
|
|
|
1, /* 0,57 % */
|
|
|
|
1, /* 1,13 % */
|
|
|
|
2, /* 2,26 % */
|
|
|
|
5, /* 4,53 % */
|
|
|
|
9, /* 9,05 % */
|
|
|
|
18, /* 18,10 % */
|
|
|
|
};
|
|
|
|
|
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_ms_rx_qual(meas, rx_qual_map[
|
|
|
|
OSMO_MIN(rx_qual_enc, ARRAY_SIZE(rx_qual_map)-1)
|
|
|
|
]);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void get_meas(struct pcu_l1_meas *meas,
|
|
|
|
const Packet_Resource_Request_t *qr)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
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_ms_c_value(meas, qr->C_VALUE);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (qr->Exist_SIGN_VAR)
|
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_ms_sign_var(meas, (qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2020-02-23 09:11:28 +00:00
|
|
|
for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->I_LEVEL_TN), ARRAY_SIZE(meas->ts)); i++)
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
2020-02-23 09:11:28 +00:00
|
|
|
if (qr->I_LEVEL_TN[i].Exist) {
|
2018-02-19 16:17:28 +00:00
|
|
|
LOGP(DRLCMAC, LOGL_INFO,
|
|
|
|
"Packet resource request: i_level[%d] = %d\n",
|
2020-02-23 09:11:28 +00:00
|
|
|
i, qr->I_LEVEL_TN[i].I_LEVEL);
|
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_ms_i_level(meas, i, -2 * qr->I_LEVEL_TN[i].I_LEVEL);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_meas(struct pcu_l1_meas *meas,
|
|
|
|
const Channel_Quality_Report_t *qr)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
get_rx_qual_meas(meas, qr->RXQUAL);
|
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_ms_c_value(meas, qr->C_VALUE);
|
|
|
|
pcu_l1_meas_set_ms_sign_var(meas, (qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++)
|
|
|
|
{
|
|
|
|
if (qr->Slot[i].Exist) {
|
|
|
|
LOGP(DRLCMAC, LOGL_DEBUG,
|
|
|
|
"Channel quality report: i_level[%d] = %d\n",
|
|
|
|
i, qr->Slot[i].I_LEVEL_TN);
|
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_ms_i_level(meas, i, -2 * qr->Slot[i].I_LEVEL_TN);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-18 11:53:54 +00:00
|
|
|
static inline void sched_ul_ass_or_rej(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_dl_tbf *tbf)
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_CHANNEL_REQUEST_DESCRIPTION);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* This call will register the new TBF with the MS on success */
|
2021-05-10 15:10:37 +00:00
|
|
|
gprs_rlcmac_ul_tbf *ul_tbf = tbf_alloc_ul_pacch(bts, tbf->ms(), tbf->trx->trx_no, tbf->tlli());
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* schedule uplink assignment or reject */
|
|
|
|
if (ul_tbf) {
|
|
|
|
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack message, so we provide one:\n");
|
2021-07-27 10:27:08 +00:00
|
|
|
osmo_fsm_inst_dispatch(tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS, NULL);
|
2018-02-19 16:17:28 +00:00
|
|
|
} else {
|
|
|
|
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack message, so we packet access reject:\n");
|
2021-07-27 10:27:08 +00:00
|
|
|
osmo_fsm_inst_dispatch(tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS_REJ, NULL);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-08 13:15:54 +00:00
|
|
|
void pdch_init(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_trx *trx, uint8_t ts_nr)
|
|
|
|
{
|
|
|
|
pdch->ts_no = ts_nr;
|
|
|
|
pdch->trx = trx;
|
|
|
|
|
|
|
|
/* Initialize the PTCCH/D message (Packet Timing Advance Control Channel) */
|
|
|
|
memset(pdch->ptcch_msg, PTCCH_TAI_FREE, PTCCH_TAI_NUM);
|
|
|
|
memset(pdch->ptcch_msg + PTCCH_TAI_NUM, PTCCH_PADDING, 7);
|
|
|
|
}
|
|
|
|
|
2018-02-19 16:17:28 +00:00
|
|
|
void gprs_rlcmac_pdch::enable()
|
|
|
|
{
|
2021-06-30 14:03:06 +00:00
|
|
|
OSMO_ASSERT(m_is_enabled == 0);
|
2018-02-19 16:17:28 +00:00
|
|
|
INIT_LLIST_HEAD(&paging_list);
|
2021-06-30 14:03:06 +00:00
|
|
|
|
|
|
|
OSMO_ASSERT(!this->ulc);
|
|
|
|
this->ulc = pdch_ulc_alloc(this, trx->bts);
|
|
|
|
|
2018-02-19 16:17:28 +00:00
|
|
|
m_is_enabled = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::disable()
|
|
|
|
{
|
2021-06-30 14:03:06 +00:00
|
|
|
OSMO_ASSERT(m_is_enabled == 1);
|
|
|
|
this->free_resources();
|
|
|
|
|
2018-02-19 16:17:28 +00:00
|
|
|
m_is_enabled = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::free_resources()
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_paging *pag;
|
|
|
|
|
|
|
|
/* kick all TBF on slot */
|
2021-01-18 16:53:29 +00:00
|
|
|
pdch_free_all_tbf(this);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* flush all pending paging messages */
|
|
|
|
while ((pag = dequeue_paging()))
|
|
|
|
talloc_free(pag);
|
|
|
|
|
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
|
|
|
talloc_free(this->ulc);
|
2021-06-30 14:03:06 +00:00
|
|
|
this->ulc = NULL;
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct gprs_rlcmac_paging *gprs_rlcmac_pdch::dequeue_paging()
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_paging *pag;
|
|
|
|
|
|
|
|
if (llist_empty(&paging_list))
|
|
|
|
return NULL;
|
2021-05-13 13:58:55 +00:00
|
|
|
pag = llist_first_entry(&paging_list, struct gprs_rlcmac_paging, list);
|
2018-02-19 16:17:28 +00:00
|
|
|
llist_del(&pag->list);
|
|
|
|
|
|
|
|
return pag;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct msgb *gprs_rlcmac_pdch::packet_paging_request()
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_paging *pag;
|
2020-02-03 16:18:03 +00:00
|
|
|
RlcMacDownlink_t *mac_control_block;
|
|
|
|
bitvec *pag_vec;
|
2018-02-19 16:17:28 +00:00
|
|
|
struct msgb *msg;
|
|
|
|
unsigned wp = 0, len;
|
2020-02-03 16:18:03 +00:00
|
|
|
int rc;
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* no paging, no message */
|
|
|
|
pag = dequeue_paging();
|
|
|
|
if (!pag)
|
|
|
|
return NULL;
|
|
|
|
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "Scheduling paging\n");
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* alloc message */
|
|
|
|
msg = msgb_alloc(23, "pag ctrl block");
|
|
|
|
if (!msg) {
|
|
|
|
talloc_free(pag);
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-02-03 16:18:03 +00:00
|
|
|
pag_vec = bitvec_alloc(23, tall_pcu_ctx);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (!pag_vec) {
|
|
|
|
msgb_free(msg);
|
|
|
|
talloc_free(pag);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
wp = Encoding::write_packet_paging_request(pag_vec);
|
|
|
|
|
|
|
|
/* loop until message is full */
|
|
|
|
while (pag) {
|
2020-08-21 13:44:58 +00:00
|
|
|
if (log_check_level(DRLCMAC, LOGL_DEBUG)) {
|
|
|
|
struct osmo_mobile_identity omi = {};
|
|
|
|
char str[64];
|
|
|
|
osmo_mobile_identity_decode(&omi, pag->identity_lv + 1, pag->identity_lv[0], true);
|
|
|
|
osmo_mobile_identity_to_str_buf(str, sizeof(str), &omi);
|
|
|
|
LOGP(DRLCMAC, LOGL_DEBUG, "Paging MI - %s\n", str);
|
|
|
|
}
|
2020-03-26 08:45:21 +00:00
|
|
|
|
2018-02-19 16:17:28 +00:00
|
|
|
/* try to add paging */
|
2020-03-26 09:18:17 +00:00
|
|
|
if ((pag->identity_lv[1] & GSM_MI_TYPE_MASK) == GSM_MI_TYPE_TMSI) {
|
2018-02-19 16:17:28 +00:00
|
|
|
/* TMSI */
|
|
|
|
len = 1 + 1 + 1 + 32 + 2 + 1;
|
|
|
|
if (pag->identity_lv[0] != 5) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_ERROR,
|
|
|
|
"TMSI paging with MI != 5 octets!\n");
|
2018-02-19 16:17:28 +00:00
|
|
|
goto continue_next;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* MI */
|
|
|
|
len = 1 + 1 + 1 + 4 + (pag->identity_lv[0]<<3) + 2 + 1;
|
|
|
|
if (pag->identity_lv[0] > 8) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_ERROR,
|
|
|
|
"Paging with MI > 8 octets!\n");
|
2018-02-19 16:17:28 +00:00
|
|
|
goto continue_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (wp + len > 184) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG,
|
|
|
|
"- Does not fit, so schedule next time\n");
|
2018-02-19 16:17:28 +00:00
|
|
|
/* put back paging record, because does not fit */
|
2020-11-23 15:04:02 +00:00
|
|
|
llist_add(&pag->list, &paging_list);
|
2018-02-19 16:17:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Encoding::write_repeated_page_info(pag_vec, wp, pag->identity_lv[0],
|
|
|
|
pag->identity_lv + 1, pag->chan_needed);
|
|
|
|
|
|
|
|
continue_next:
|
|
|
|
talloc_free(pag);
|
|
|
|
pag = dequeue_paging();
|
|
|
|
}
|
|
|
|
|
|
|
|
bitvec_pack(pag_vec, msgb_put(msg, 23));
|
2020-02-03 16:18:03 +00:00
|
|
|
mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n");
|
2020-02-03 16:18:03 +00:00
|
|
|
rc = decode_gsm_rlcmac_downlink(pag_vec, mac_control_block);
|
|
|
|
if (rc < 0) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_ERROR, "Decoding of Downlink Packet Paging Request failed (%d): %s\n",
|
2020-11-23 15:36:42 +00:00
|
|
|
rc, osmo_hexdump(msgb_data(msg), msgb_length(msg)));
|
2020-02-03 16:18:03 +00:00
|
|
|
goto free_ret;
|
|
|
|
}
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n");
|
2018-02-19 16:17:28 +00:00
|
|
|
bitvec_free(pag_vec);
|
|
|
|
talloc_free(mac_control_block);
|
|
|
|
return msg;
|
2020-02-03 16:18:03 +00:00
|
|
|
|
|
|
|
free_ret:
|
|
|
|
bitvec_free(pag_vec);
|
|
|
|
talloc_free(mac_control_block);
|
|
|
|
msgb_free(msg);
|
|
|
|
return NULL;
|
2018-02-19 16:17:28 +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
|
|
|
bool gprs_rlcmac_pdch::add_paging(uint8_t chan_needed, const struct osmo_mobile_identity *mi)
|
2018-02-19 16:17:28 +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
|
|
|
int rc;
|
2018-02-19 16:17:28 +00:00
|
|
|
struct gprs_rlcmac_paging *pag = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_paging);
|
|
|
|
if (!pag)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
pag->chan_needed = chan_needed;
|
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_encode_buf(pag->identity_lv + 1, sizeof(pag->identity_lv) - 1, mi, true);
|
|
|
|
if (rc <= 0) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_ERROR, "Cannot encode Mobile Identity (rc=%d)\n", rc);
|
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
|
|
|
talloc_free(pag);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pag->identity_lv[0] = rc;
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
llist_add(&pag->list, &paging_list);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, uint32_t fn)
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_tbf *tbf, *new_tbf;
|
|
|
|
uint32_t tlli = packet->TLLI;
|
2021-06-22 20:15:20 +00:00
|
|
|
GprsMs *ms;
|
2018-02-19 16:17:28 +00:00
|
|
|
gprs_rlcmac_ul_tbf *ul_tbf;
|
2021-03-29 16:15:30 +00:00
|
|
|
enum pdch_ulc_tbf_poll_reason reason;
|
2021-03-09 16:18:12 +00:00
|
|
|
struct pdch_ulc_node *poll;
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-03-09 16:18:12 +00:00
|
|
|
poll = pdch_ulc_get_node(ulc, fn);
|
|
|
|
if (!poll || poll->type !=PDCH_ULC_NODE_TBF_POLL || !poll->tbf_poll.poll_tbf) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with "
|
2018-02-19 16:17:28 +00:00
|
|
|
"unknown FN=%u TLLI=0x%08x (TRX %d TS %d)\n",
|
|
|
|
fn, tlli, trx_no(), ts_no);
|
2021-06-22 20:15:20 +00:00
|
|
|
ms = bts_ms_by_tlli(bts(), tlli, GSM_RESERVED_TMSI);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (ms)
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with "
|
|
|
|
"unknown TBF corresponds to MS with IMSI %s, TA %d, "
|
|
|
|
"uTBF (TFI=%d, state=%s), dTBF (TFI=%d, state=%s)\n",
|
|
|
|
ms_imsi(ms), ms_ta(ms),
|
|
|
|
ms_ul_tbf(ms) ? ms_ul_tbf(ms)->tfi() : 0,
|
|
|
|
ms_ul_tbf(ms) ? ms_ul_tbf(ms)->state_name() : "None",
|
|
|
|
ms_dl_tbf(ms) ? ms_dl_tbf(ms)->tfi() : 0,
|
|
|
|
ms_dl_tbf(ms) ? ms_dl_tbf(ms)->state_name() : "None");
|
2018-02-19 16:17:28 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-03-09 16:18:12 +00:00
|
|
|
tbf = poll->tbf_poll.poll_tbf;
|
2021-03-29 16:15:30 +00:00
|
|
|
reason = poll->tbf_poll.reason;
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* Reset N3101 counter: */
|
2018-02-20 17:16:11 +00:00
|
|
|
tbf->n_reset(N3101);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);
|
2021-06-22 20:15:20 +00:00
|
|
|
/* Gather MS from TBF, since it may be NULL or may have been merged during update_ms */
|
|
|
|
ms = tbf->ms();
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-06-07 16:13:23 +00:00
|
|
|
LOGPTBF(tbf, LOGL_DEBUG, "FN=%" PRIu32 " Rx Packet Control Ack (reason=%s)\n",
|
|
|
|
fn, get_value_string(pdch_ulc_tbf_poll_reason_names, reason));
|
2021-03-09 16:18:12 +00:00
|
|
|
pdch_ulc_release_fn(ulc, fn);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* check if this control ack belongs to packet uplink ack */
|
|
|
|
ul_tbf = as_ul_tbf(tbf);
|
2021-07-29 16:39:16 +00:00
|
|
|
if (ul_tbf && reason == PDCH_ULC_POLL_UL_ACK && tbf_ul_ack_exp_ctrl_ack(ul_tbf, fn, ts_no)) {
|
|
|
|
osmo_fsm_inst_dispatch(ul_tbf->ul_ack_fsm.fi, TBF_UL_ACK_EV_RX_CTRL_ACK, NULL);
|
|
|
|
/* We can free since we only set polling on final UL ACK/NACK */
|
2018-02-19 16:17:28 +00:00
|
|
|
LOGPTBF(tbf, LOGL_DEBUG, "[UPLINK] END\n");
|
|
|
|
tbf_free(tbf);
|
|
|
|
return;
|
|
|
|
}
|
2021-07-27 15:33:07 +00:00
|
|
|
if (tbf->dl_ass_state_is(TBF_DL_ASS_WAIT_ACK)) {
|
2018-02-19 16:17:28 +00:00
|
|
|
LOGPTBF(tbf, LOGL_DEBUG, "[UPLINK] DOWNLINK ASSIGNED\n");
|
|
|
|
/* reset N3105 */
|
2018-02-20 17:16:11 +00:00
|
|
|
tbf->n_reset(N3105);
|
2021-07-27 15:33:07 +00:00
|
|
|
osmo_fsm_inst_dispatch(tbf->dl_ass_fsm.fi, TBF_DL_ASS_EV_RX_ASS_CTRL_ACK, NULL);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-06-22 20:15:20 +00:00
|
|
|
new_tbf = ms_dl_tbf(ms);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (!new_tbf) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_ERROR, "Got ACK, but DL "
|
2018-02-19 16:17:28 +00:00
|
|
|
"TBF is gone TLLI=0x%08x\n", tlli);
|
|
|
|
return;
|
|
|
|
}
|
2021-05-14 10:50:46 +00:00
|
|
|
if (tbf->state_is(TBF_ST_WAIT_RELEASE) &&
|
2018-02-19 16:17:28 +00:00
|
|
|
tbf->direction == new_tbf->direction)
|
|
|
|
tbf_free(tbf);
|
|
|
|
|
2021-07-22 17:56:37 +00:00
|
|
|
osmo_fsm_inst_dispatch(new_tbf->state_fsm.fi, TBF_EV_ASSIGN_ACK_PACCH, NULL);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
tbf_assign_control_ts(new_tbf);
|
|
|
|
return;
|
|
|
|
}
|
2021-07-27 10:27:08 +00:00
|
|
|
if (tbf->ul_ass_state_is(TBF_UL_ASS_WAIT_ACK)) {
|
2018-02-19 16:17:28 +00:00
|
|
|
LOGPTBF(tbf, LOGL_DEBUG, "[DOWNLINK] UPLINK ASSIGNED\n");
|
|
|
|
/* reset N3105 */
|
2018-02-20 17:16:11 +00:00
|
|
|
tbf->n_reset(N3105);
|
2021-07-27 10:27:08 +00:00
|
|
|
osmo_fsm_inst_dispatch(tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_RX_ASS_CTRL_ACK, NULL);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-06-22 20:15:20 +00:00
|
|
|
new_tbf = ms_ul_tbf(ms);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (!new_tbf) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_ERROR, "Got ACK, but UL "
|
2018-02-19 16:17:28 +00:00
|
|
|
"TBF is gone TLLI=0x%08x\n", tlli);
|
|
|
|
return;
|
|
|
|
}
|
2021-05-14 10:50:46 +00:00
|
|
|
if (tbf->state_is(TBF_ST_WAIT_RELEASE) &&
|
2018-02-19 16:17:28 +00:00
|
|
|
tbf->direction == new_tbf->direction)
|
|
|
|
tbf_free(tbf);
|
|
|
|
|
2021-07-22 17:56:37 +00:00
|
|
|
osmo_fsm_inst_dispatch(new_tbf->state_fsm.fi, TBF_EV_ASSIGN_ACK_PACCH, NULL);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
tbf_assign_control_ts(new_tbf);
|
|
|
|
/* there might be LLC packets waiting in the queue, but the DL
|
|
|
|
* TBF might have been released while the UL TBF has been
|
|
|
|
* established */
|
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_need_dl_tbf(new_tbf->ms()))
|
2018-02-19 16:17:28 +00:00
|
|
|
new_tbf->establish_dl_tbf_on_pacch();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2021-02-01 13:52:48 +00:00
|
|
|
if (ms->nacc && ms->nacc->fi->state == NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK &&
|
|
|
|
ms->nacc->continue_poll_fn == fn && ms->nacc->continue_poll_ts == ts_no) {
|
|
|
|
osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_RX_CELL_CHG_CONTINUE_ACK, NULL);
|
|
|
|
/* Don't assume MS is no longer reachable (hence don't free) after this: TS 44.060
|
|
|
|
* "When the mobile station receives the PACKET CELL CHANGE ORDER
|
|
|
|
* or the PACKET CELL CHANGE CONTINUE message the mobile station
|
|
|
|
* shall transmit a PACKET CONTROL ACKNOWLEDGMENT message in the
|
|
|
|
* specified uplink radio block if a valid RRBP field is
|
|
|
|
* received as part of the message; the mobile station _MAY_ then
|
|
|
|
* switch to a new cell."
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
2021-06-07 16:13:23 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_ERROR, "FN=%" PRIu32 " "
|
|
|
|
"Error: received PACKET CONTROL ACK at no request (reason=%s)\n", fn,
|
|
|
|
get_value_string(pdch_ulc_tbf_poll_reason_names, reason));
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
2019-09-25 11:46:14 +00:00
|
|
|
void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_nack, uint32_t fn, struct pcu_l1_meas *meas)
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
|
|
|
int8_t tfi = 0; /* must be signed */
|
2021-03-09 16:18:12 +00:00
|
|
|
struct pdch_ulc_node *poll;
|
2018-02-19 16:17:28 +00:00
|
|
|
struct gprs_rlcmac_dl_tbf *tbf;
|
|
|
|
int rc;
|
|
|
|
int num_blocks;
|
|
|
|
uint8_t bits_data[RLC_GPRS_WS/8];
|
|
|
|
bitvec bits;
|
|
|
|
int bsn_begin, bsn_end;
|
|
|
|
char show_bits[RLC_GPRS_WS + 1];
|
|
|
|
|
|
|
|
tfi = ack_nack->DOWNLINK_TFI;
|
2021-03-09 16:18:12 +00:00
|
|
|
poll = pdch_ulc_get_node(ulc, fn);
|
|
|
|
if (!poll || poll->type != PDCH_ULC_NODE_TBF_POLL) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "PACKET DOWNLINK ACK with "
|
2018-02-19 16:17:28 +00:00
|
|
|
"unknown FN=%u TFI=%d (TRX %d TS %d)\n",
|
|
|
|
fn, tfi, trx_no(), ts_no);
|
|
|
|
return;
|
|
|
|
}
|
2021-03-09 16:18:12 +00:00
|
|
|
tbf = as_dl_tbf(poll->tbf_poll.poll_tbf);
|
2021-08-23 14:58:04 +00:00
|
|
|
if (tbf->tfi() != tfi) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPTBFDL(tbf, LOGL_NOTICE,
|
|
|
|
"PACKET DOWNLINK ACK with wrong TFI=%d, ignoring!\n", tfi);
|
2018-02-19 16:17:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset N3101 counter: */
|
2018-02-20 17:16:11 +00:00
|
|
|
tbf->n_reset(N3101);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-03-09 16:18:12 +00:00
|
|
|
pdch_ulc_release_fn(ulc, fn);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
LOGPTBF(tbf, LOGL_DEBUG, "RX: [PCU <- BTS] Packet Downlink Ack/Nack\n");
|
|
|
|
|
|
|
|
bits.data = bits_data;
|
|
|
|
bits.data_len = sizeof(bits_data);
|
|
|
|
bits.cur_bit = 0;
|
|
|
|
|
|
|
|
num_blocks = Decoding::decode_gprs_acknack_bits(
|
|
|
|
&ack_nack->Ack_Nack_Description, &bits,
|
2020-10-23 19:00:23 +00:00
|
|
|
&bsn_begin, &bsn_end, static_cast<gprs_rlc_dl_window *>(tbf->window()));
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG,
|
2018-02-19 16:17:28 +00:00
|
|
|
"Got GPRS DL ACK bitmap: SSN: %d, BSN %d to %d - 1 (%d blocks), "
|
|
|
|
"\"%s\"\n",
|
|
|
|
ack_nack->Ack_Nack_Description.STARTING_SEQUENCE_NUMBER,
|
|
|
|
bsn_begin, bsn_end, num_blocks,
|
|
|
|
(Decoding::extract_rbb(&bits, show_bits), show_bits));
|
|
|
|
|
|
|
|
rc = tbf->rcvd_dl_ack(
|
|
|
|
ack_nack->Ack_Nack_Description.FINAL_ACK_INDICATION,
|
|
|
|
bsn_begin, &bits);
|
|
|
|
if (rc == 1) {
|
|
|
|
tbf_free(tbf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* check for channel request */
|
|
|
|
if (ack_nack->Exist_Channel_Request_Description)
|
2021-01-18 11:53:54 +00:00
|
|
|
sched_ul_ass_or_rej(bts(), tbf);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* get measurements */
|
|
|
|
if (tbf->ms()) {
|
2019-09-25 11:46:14 +00:00
|
|
|
get_meas(meas, &ack_nack->Channel_Quality_Report);
|
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
|
|
|
ms_update_l1_meas(tbf->ms(), meas);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-25 11:46:14 +00:00
|
|
|
void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nack, uint32_t fn, struct pcu_l1_meas *meas)
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
|
|
|
int8_t tfi = 0; /* must be signed */
|
|
|
|
struct gprs_rlcmac_dl_tbf *tbf;
|
2021-03-09 16:18:12 +00:00
|
|
|
struct pdch_ulc_node *poll;
|
2020-10-23 19:00:23 +00:00
|
|
|
gprs_rlc_dl_window *window;
|
2018-02-19 16:17:28 +00:00
|
|
|
int rc;
|
|
|
|
int num_blocks;
|
|
|
|
uint8_t bits_data[RLC_EGPRS_MAX_WS/8];
|
|
|
|
char show_bits[RLC_EGPRS_MAX_WS + 1];
|
|
|
|
bitvec bits;
|
|
|
|
int bsn_begin, bsn_end;
|
|
|
|
|
|
|
|
tfi = ack_nack->DOWNLINK_TFI;
|
2021-03-09 16:18:12 +00:00
|
|
|
poll = pdch_ulc_get_node(ulc, fn);
|
|
|
|
if (!poll || poll->type !=PDCH_ULC_NODE_TBF_POLL) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
|
2018-02-19 16:17:28 +00:00
|
|
|
"unknown FN=%u TFI=%d (TRX %d TS %d)\n",
|
|
|
|
fn, tfi, trx_no(), ts_no);
|
|
|
|
return;
|
|
|
|
}
|
2021-03-09 16:18:12 +00:00
|
|
|
tbf = as_dl_tbf(poll->tbf_poll.poll_tbf);
|
2021-08-23 14:58:04 +00:00
|
|
|
if (tbf->tfi() != tfi) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
|
2018-02-19 16:17:28 +00:00
|
|
|
"wrong TFI=%d, ignoring!\n", tfi);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset N3101 counter: */
|
2018-02-20 17:16:11 +00:00
|
|
|
tbf->n_reset(N3101);
|
2021-03-09 16:18:12 +00:00
|
|
|
pdch_ulc_release_fn(ulc, fn);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
LOGPTBF(tbf, LOGL_DEBUG,
|
|
|
|
"RX: [PCU <- BTS] EGPRS Packet Downlink Ack/Nack\n");
|
|
|
|
|
2020-10-23 19:00:23 +00:00
|
|
|
window = static_cast<gprs_rlc_dl_window *>(tbf->window());
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "EGPRS ACK/NACK: "
|
2018-02-19 16:17:28 +00:00
|
|
|
"ut: %d, final: %d, bow: %d, eow: %d, ssn: %d, have_crbb: %d, "
|
|
|
|
"urbb_len:%d, %p, %p, %d, %d, win: %d-%d, urbb: %s\n",
|
|
|
|
(int)ack_nack->EGPRS_AckNack.UnionType,
|
|
|
|
(int)ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
|
|
|
|
(int)ack_nack->EGPRS_AckNack.Desc.BEGINNING_OF_WINDOW,
|
|
|
|
(int)ack_nack->EGPRS_AckNack.Desc.END_OF_WINDOW,
|
|
|
|
(int)ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER,
|
|
|
|
(int)ack_nack->EGPRS_AckNack.Desc.Exist_CRBB,
|
|
|
|
(int)ack_nack->EGPRS_AckNack.Desc.URBB_LENGTH,
|
|
|
|
(void *)&ack_nack->EGPRS_AckNack.UnionType,
|
|
|
|
(void *)&ack_nack->EGPRS_AckNack.Desc,
|
|
|
|
(int)offsetof(EGPRS_AckNack_t, Desc),
|
|
|
|
(int)offsetof(EGPRS_AckNack_w_len_t, Desc),
|
2020-10-23 19:00:23 +00:00
|
|
|
window->v_a(),
|
|
|
|
window->v_s(),
|
2018-02-19 16:17:28 +00:00
|
|
|
osmo_hexdump((const uint8_t *)&ack_nack->EGPRS_AckNack.Desc.URBB,
|
|
|
|
sizeof(ack_nack->EGPRS_AckNack.Desc.URBB)));
|
|
|
|
|
|
|
|
bits.data = bits_data;
|
|
|
|
bits.data_len = sizeof(bits_data);
|
|
|
|
bits.cur_bit = 0;
|
|
|
|
|
|
|
|
num_blocks = Decoding::decode_egprs_acknack_bits(
|
|
|
|
&ack_nack->EGPRS_AckNack.Desc, &bits,
|
2020-10-23 19:00:23 +00:00
|
|
|
&bsn_begin, &bsn_end, window);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG,
|
2018-02-19 16:17:28 +00:00
|
|
|
"Got EGPRS DL ACK bitmap: SSN: %d, BSN %d to %d - 1 (%d blocks), "
|
|
|
|
"\"%s\"\n",
|
|
|
|
ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER,
|
|
|
|
bsn_begin, bsn_end, num_blocks,
|
|
|
|
(Decoding::extract_rbb(&bits, show_bits), show_bits)
|
|
|
|
);
|
|
|
|
|
|
|
|
rc = tbf->rcvd_dl_ack(
|
|
|
|
ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
|
|
|
|
bsn_begin, &bits);
|
|
|
|
if (rc == 1) {
|
|
|
|
tbf_free(tbf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for channel request */
|
|
|
|
if (ack_nack->Exist_ChannelRequestDescription)
|
2021-01-18 11:53:54 +00:00
|
|
|
sched_ul_ass_or_rej(bts(), tbf);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* get measurements */
|
|
|
|
if (tbf->ms()) {
|
|
|
|
/* TODO: Implement Measurements parsing for EGPRS */
|
|
|
|
/*
|
2019-09-25 11:46:14 +00:00
|
|
|
get_meas(meas, &ack_nack->Channel_Quality_Report);
|
|
|
|
tbf->ms()->update_l1_meas(meas);
|
2018-02-19 16:17:28 +00:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-25 11:46:14 +00:00
|
|
|
void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn, struct pcu_l1_meas *meas)
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
|
|
|
struct gprs_rlcmac_sba *sba;
|
|
|
|
|
|
|
|
if (request->ID.UnionType) {
|
2021-04-22 17:18:13 +00:00
|
|
|
struct gprs_rlcmac_ul_tbf *ul_tbf = NULL;
|
|
|
|
struct pdch_ulc_node *item;
|
2018-02-19 16:17:28 +00:00
|
|
|
uint32_t tlli = request->ID.u.TLLI;
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
GprsMs *ms = bts_ms_by_tlli(bts(), tlli, GSM_RESERVED_TMSI);
|
2020-05-12 17:20:10 +00:00
|
|
|
if (!ms) {
|
2021-01-14 15:48:38 +00:00
|
|
|
ms = bts_alloc_ms(bts(), 0, 0); /* ms class updated later */
|
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
|
|
|
ms_set_tlli(ms, tlli);
|
2020-05-12 17:20:10 +00:00
|
|
|
}
|
2020-05-08 15:44:33 +00:00
|
|
|
|
2018-02-19 16:17:28 +00:00
|
|
|
/* Keep the ms, even if it gets idle temporarily */
|
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
|
|
|
ms_ref(ms);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-04-22 17:18:13 +00:00
|
|
|
if (!(item = pdch_ulc_get_node(ulc, fn))) {
|
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: "
|
|
|
|
"UL block not reserved\n", fn);
|
|
|
|
goto return_unref;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (item->type) {
|
|
|
|
case PDCH_ULC_NODE_SBA:
|
|
|
|
sba = item->sba.sba;
|
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "FN=%u PKT RESOURCE REQ: "
|
|
|
|
"MS requests UL TBF throguh SBA\n", fn);
|
Convert GprsMS and helpers classes to C
As we integrate osmo-pcu more and more with libosmocore features, it
becomes really hard to use them since libosmocore relies heavily on C
specific compilation features, which are not available in old C++
compilers (such as designated initializers for complex types in FSMs).
GprsMs is right now a quite simple object since initial design of
osmo-pcu made it optional and most of the logic was placed and stored
duplicated in TBF objects. However, that's changing as we introduce more
features, with the GprsMS class getting more weight. Hence, let's move
it now to be a C struct in order to be able to easily use libosmocore
features there, such as FSMs.
Some helper classes which GprsMs uses are also mostly move to C since
they are mostly structs with methods, so there's no point in having
duplicated APIs for C++ and C for such simple cases.
For some more complex classes, like (ul_,dl_)tbf, C API bindings are
added where needed so that GprsMs can use functionalitites from that
class. Most of those APIs can be kept afterwards and drop the C++ ones
since they provide no benefit in general.
Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c
2020-12-16 14:59:45 +00:00
|
|
|
ms_set_ta(ms, sba->ta);
|
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
|
|
|
sba_free(sba);
|
2021-04-22 17:18:13 +00:00
|
|
|
break;
|
|
|
|
case PDCH_ULC_NODE_TBF_POLL:
|
|
|
|
if (item->tbf_poll.poll_tbf->direction != GPRS_RLCMAC_UL_TBF) {
|
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: "
|
|
|
|
"Unexpectedly received for DL TBF %s\n", fn,
|
|
|
|
tbf_name(item->tbf_poll.poll_tbf));
|
|
|
|
/* let common path expire the poll */
|
|
|
|
goto return_unref;
|
|
|
|
}
|
|
|
|
ul_tbf = (struct gprs_rlcmac_ul_tbf *)item->tbf_poll.poll_tbf;
|
|
|
|
if (item->tbf_poll.reason != PDCH_ULC_POLL_UL_ACK) {
|
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: "
|
|
|
|
"Unexpectedly received, waiting for poll reason %d\n",
|
|
|
|
fn, item->tbf_poll.reason);
|
|
|
|
/* let common path expire the poll */
|
|
|
|
goto return_unref;
|
|
|
|
}
|
|
|
|
if (ul_tbf != ms_ul_tbf(ms)) {
|
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: "
|
|
|
|
"Unexpected TLLI 0x%08x received vs exp 0x%08x\n",
|
|
|
|
fn, tlli, ul_tbf->tlli());
|
|
|
|
/* let common path expire the poll */
|
|
|
|
goto return_unref;
|
|
|
|
}
|
|
|
|
/* 3GPP TS 44.060 $ 9.3.3.3 */
|
|
|
|
LOGPTBFUL(ul_tbf, LOGL_DEBUG, "FN=%u PKT RESOURCE REQ: "
|
|
|
|
"MS requests reuse of finished UL TBF in RRBP "
|
|
|
|
"block of final UL ACK/NACK\n", fn);
|
|
|
|
ul_tbf->n_reset(N3103);
|
|
|
|
pdch_ulc_release_node(ulc, item);
|
|
|
|
break;
|
|
|
|
case PDCH_ULC_NODE_TBF_USF:
|
|
|
|
/* Is it actually valid for an MS to send a PKT Res Req during USF? */
|
|
|
|
ul_tbf = item->tbf_usf.ul_tbf;
|
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: "
|
|
|
|
"Unexpectedly received, waiting USF of %s\n",
|
|
|
|
fn, tbf_name(item->tbf_usf.ul_tbf));
|
|
|
|
pdch_ulc_release_node(ulc, item);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
OSMO_ASSERT(0);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
2021-04-22 17:18:13 +00:00
|
|
|
|
|
|
|
/* here ul_tbf may be NULL in SBA case (no previous TBF) */
|
2020-07-08 15:35:12 +00:00
|
|
|
|
2020-03-23 17:49:16 +00:00
|
|
|
if (request->Exist_MS_Radio_Access_capability2) {
|
2020-05-08 15:44:33 +00:00
|
|
|
uint8_t ms_class, egprs_ms_class;
|
2021-01-18 16:14:14 +00:00
|
|
|
ms_class = get_ms_class_by_capability(&request->MS_Radio_Access_capability2);
|
|
|
|
egprs_ms_class = get_egprs_ms_class_by_capability(&request->MS_Radio_Access_capability2);
|
2020-07-08 15:18:22 +00:00
|
|
|
if (ms_class)
|
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
|
|
|
ms_set_ms_class(ms, ms_class);
|
2020-07-08 15:18:22 +00:00
|
|
|
if (egprs_ms_class)
|
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
|
|
|
ms_set_egprs_ms_class(ms, egprs_ms_class);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
2020-05-08 15:44:33 +00:00
|
|
|
|
2020-07-08 15:35:12 +00:00
|
|
|
/* Get rid of previous finished UL TBF before providing a new one */
|
2021-04-22 17:18:13 +00:00
|
|
|
if (ul_tbf) {
|
2021-05-14 10:50:46 +00:00
|
|
|
if (!ul_tbf->state_is(TBF_ST_FINISHED))
|
2020-07-08 15:35:12 +00:00
|
|
|
LOGPTBFUL(ul_tbf, LOGL_NOTICE,
|
|
|
|
"Got PACKET RESOURCE REQ while TBF not finished, killing pending UL TBF\n");
|
|
|
|
tbf_free(ul_tbf);
|
|
|
|
}
|
|
|
|
|
2021-05-10 15:10:37 +00:00
|
|
|
ul_tbf = tbf_alloc_ul_pacch(bts(), ms, trx_no(), tlli);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (!ul_tbf) {
|
2021-04-26 14:48:34 +00:00
|
|
|
handle_tbf_reject(bts(), ms, trx_no(), ts_no);
|
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
|
|
|
goto return_unref;
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set control ts to current MS's TS, until assignment complete */
|
2019-12-24 12:02:48 +00:00
|
|
|
LOGPTBF(ul_tbf, LOGL_DEBUG, "change control TS %d -> %d until assignment is complete.\n",
|
2018-02-19 16:17:28 +00:00
|
|
|
ul_tbf->control_ts, ts_no);
|
|
|
|
|
|
|
|
ul_tbf->control_ts = ts_no;
|
|
|
|
/* schedule uplink assignment */
|
2021-07-27 10:27:08 +00:00
|
|
|
osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS, NULL);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* get measurements */
|
2021-04-22 17:18:13 +00:00
|
|
|
get_meas(meas, request);
|
|
|
|
ms_update_l1_meas(ul_tbf->ms(), meas);
|
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
|
|
|
return_unref:
|
|
|
|
ms_unref(ms);
|
2018-02-19 16:17:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (request->ID.u.Global_TFI.UnionType) {
|
|
|
|
struct gprs_rlcmac_dl_tbf *dl_tbf;
|
|
|
|
int8_t tfi = request->ID.u.Global_TFI.u.DOWNLINK_TFI;
|
2021-01-14 15:48:38 +00:00
|
|
|
dl_tbf = bts_dl_tbf_by_tfi(bts(), tfi, trx_no(), ts_no);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (!dl_tbf) {
|
2018-10-06 08:42:58 +00:00
|
|
|
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESOURCE REQ unknown downlink TFI=%d\n", tfi);
|
2018-02-19 16:17:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
LOGPTBFDL(dl_tbf, LOGL_ERROR,
|
|
|
|
"RX: [PCU <- BTS] FIXME: Packet resource request\n");
|
|
|
|
|
|
|
|
/* Reset N3101 counter: */
|
2018-02-20 17:16:11 +00:00
|
|
|
dl_tbf->n_reset(N3101);
|
2018-02-19 16:17:28 +00:00
|
|
|
} else {
|
|
|
|
struct gprs_rlcmac_ul_tbf *ul_tbf;
|
|
|
|
int8_t tfi = request->ID.u.Global_TFI.u.UPLINK_TFI;
|
2021-01-14 15:48:38 +00:00
|
|
|
ul_tbf = bts_ul_tbf_by_tfi(bts(), tfi, trx_no(), ts_no);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (!ul_tbf) {
|
2018-10-06 08:42:58 +00:00
|
|
|
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESOURCE REQ unknown uplink TFI=%d\n", tfi);
|
2018-02-19 16:17:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
LOGPTBFUL(ul_tbf, LOGL_ERROR,
|
|
|
|
"RX: [PCU <- BTS] FIXME: Packet resource request\n");
|
|
|
|
|
|
|
|
/* Reset N3101 counter: */
|
2018-02-20 17:16:11 +00:00
|
|
|
ul_tbf->n_reset(N3101);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *report, uint32_t fn)
|
|
|
|
{
|
2020-08-18 18:29:40 +00:00
|
|
|
struct gprs_rlcmac_sba *sba;
|
2021-03-09 16:18:12 +00:00
|
|
|
struct pdch_ulc_node *poll;
|
2020-08-18 18:29:40 +00:00
|
|
|
GprsMs *ms;
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
ms = bts_ms_by_tlli(bts(), report->TLLI, GSM_RESERVED_TMSI);
|
2020-08-18 18:29:40 +00:00
|
|
|
if (!ms) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "MS send measurement "
|
|
|
|
"but TLLI 0x%08x is unknown\n", report->TLLI);
|
2021-01-14 15:48:38 +00:00
|
|
|
ms = bts_alloc_ms(bts(), 0, 0);
|
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
|
|
|
ms_set_tlli(ms, report->TLLI);
|
2020-08-18 18:29:40 +00:00
|
|
|
}
|
2021-03-09 16:18:12 +00:00
|
|
|
if ((poll = pdch_ulc_get_node(ulc, fn))) {
|
|
|
|
switch (poll->type) {
|
|
|
|
case PDCH_ULC_NODE_TBF_USF:
|
2021-03-24 13:06:15 +00:00
|
|
|
pdch_ulc_release_fn(ulc, fn);
|
2021-03-09 16:18:12 +00:00
|
|
|
break;
|
|
|
|
case PDCH_ULC_NODE_TBF_POLL:
|
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_INFO, "FN=%" PRIu32 " Rx Meas Report "
|
|
|
|
"on RRBP POLL, this probably means a DL/CTRL ACK/NACk will "
|
|
|
|
"need to be polled again later\n", fn);
|
|
|
|
pdch_ulc_release_fn(ulc, fn);
|
|
|
|
break;
|
|
|
|
case PDCH_ULC_NODE_SBA:
|
|
|
|
sba = poll->sba.sba;
|
|
|
|
ms_set_ta(ms, sba->ta);
|
|
|
|
sba_free(sba);
|
|
|
|
break;
|
|
|
|
}
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
2020-08-18 18:29:40 +00:00
|
|
|
gprs_rlcmac_meas_rep(ms, report);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
Introduce NACC support
A new nacc_fsm is introduced per MS object, with its partner priv
structure struct nacc_fsm_ctx, which exists and is available in the MS
object only during the duration of the NACC procedure.
The NACC context is created on an MS whenever a Pkt Cell Change
Notification is received on Uplink RLCMAC, which asks for neighbor
information of a given ARFCN+BSIC.
First, the target ARFCN+BSIC needs to be translated into a CGI-PS
(RAC+CI) address. That's done by asking the BSC through the Neighbour
Resolution Service available in osmo-bsc using the CTRL interface.
Once the CGI-PS of the target cell is known, PCU starts a RIM RAN-INFO
request against the SGSN (which will route the request as needed), and
wait for a response containing the SI bits from the target cell.
After the SI are received, the scheduler is instructed to eventually
poll a TBF for the MS originating the CCN, so that we can send the SI
encapsulated into multiple Packet Neighbor Cell Data messages on the
downlink.
One all the SI bits are sent, the scheduler is instructed to send a
Packet Cell Change Continue message.
Once the message above has been sent, the FSM autodestroys itself.
Caches are also introduced in this patch which allows for re-using
recently known translations ARFCN+BSIC -> CGI-PS and CGI-PS -> SI_INFO
respectively.
Change-Id: Id35f40d05f3e081f32fddbf1fa34cb338db452ca
2021-01-21 17:46:13 +00:00
|
|
|
void gprs_rlcmac_pdch::rcv_cell_change_notification(Packet_Cell_Change_Notification_t *notif,
|
|
|
|
uint32_t fn, struct pcu_l1_meas *meas)
|
|
|
|
{
|
|
|
|
GprsMs *ms;
|
|
|
|
|
|
|
|
bts_do_rate_ctr_inc(bts(), CTR_PKT_CELL_CHG_NOTIFICATION);
|
|
|
|
|
|
|
|
if (notif->Global_TFI.UnionType == 0) {
|
|
|
|
struct gprs_rlcmac_ul_tbf *ul_tbf = ul_tbf_by_tfi(notif->Global_TFI.u.UPLINK_TFI);
|
|
|
|
if (!ul_tbf) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "UL TBF TFI=0x%2x not found\n", notif->Global_TFI.u.UPLINK_TFI);
|
Introduce NACC support
A new nacc_fsm is introduced per MS object, with its partner priv
structure struct nacc_fsm_ctx, which exists and is available in the MS
object only during the duration of the NACC procedure.
The NACC context is created on an MS whenever a Pkt Cell Change
Notification is received on Uplink RLCMAC, which asks for neighbor
information of a given ARFCN+BSIC.
First, the target ARFCN+BSIC needs to be translated into a CGI-PS
(RAC+CI) address. That's done by asking the BSC through the Neighbour
Resolution Service available in osmo-bsc using the CTRL interface.
Once the CGI-PS of the target cell is known, PCU starts a RIM RAN-INFO
request against the SGSN (which will route the request as needed), and
wait for a response containing the SI bits from the target cell.
After the SI are received, the scheduler is instructed to eventually
poll a TBF for the MS originating the CCN, so that we can send the SI
encapsulated into multiple Packet Neighbor Cell Data messages on the
downlink.
One all the SI bits are sent, the scheduler is instructed to send a
Packet Cell Change Continue message.
Once the message above has been sent, the FSM autodestroys itself.
Caches are also introduced in this patch which allows for re-using
recently known translations ARFCN+BSIC -> CGI-PS and CGI-PS -> SI_INFO
respectively.
Change-Id: Id35f40d05f3e081f32fddbf1fa34cb338db452ca
2021-01-21 17:46:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
ms = ul_tbf->ms();
|
|
|
|
} else if (notif->Global_TFI.UnionType == 1) {
|
|
|
|
struct gprs_rlcmac_dl_tbf *dl_tbf = dl_tbf_by_tfi(notif->Global_TFI.u.DOWNLINK_TFI);
|
|
|
|
if (!dl_tbf) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "DL TBF TFI=0x%2x not found\n", notif->Global_TFI.u.DOWNLINK_TFI);
|
Introduce NACC support
A new nacc_fsm is introduced per MS object, with its partner priv
structure struct nacc_fsm_ctx, which exists and is available in the MS
object only during the duration of the NACC procedure.
The NACC context is created on an MS whenever a Pkt Cell Change
Notification is received on Uplink RLCMAC, which asks for neighbor
information of a given ARFCN+BSIC.
First, the target ARFCN+BSIC needs to be translated into a CGI-PS
(RAC+CI) address. That's done by asking the BSC through the Neighbour
Resolution Service available in osmo-bsc using the CTRL interface.
Once the CGI-PS of the target cell is known, PCU starts a RIM RAN-INFO
request against the SGSN (which will route the request as needed), and
wait for a response containing the SI bits from the target cell.
After the SI are received, the scheduler is instructed to eventually
poll a TBF for the MS originating the CCN, so that we can send the SI
encapsulated into multiple Packet Neighbor Cell Data messages on the
downlink.
One all the SI bits are sent, the scheduler is instructed to send a
Packet Cell Change Continue message.
Once the message above has been sent, the FSM autodestroys itself.
Caches are also introduced in this patch which allows for re-using
recently known translations ARFCN+BSIC -> CGI-PS and CGI-PS -> SI_INFO
respectively.
Change-Id: Id35f40d05f3e081f32fddbf1fa34cb338db452ca
2021-01-21 17:46:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
ms = dl_tbf->ms();
|
|
|
|
} else { OSMO_ASSERT(0); }
|
|
|
|
|
2021-03-24 13:05:04 +00:00
|
|
|
pdch_ulc_release_fn(ulc, fn);
|
|
|
|
|
Introduce NACC support
A new nacc_fsm is introduced per MS object, with its partner priv
structure struct nacc_fsm_ctx, which exists and is available in the MS
object only during the duration of the NACC procedure.
The NACC context is created on an MS whenever a Pkt Cell Change
Notification is received on Uplink RLCMAC, which asks for neighbor
information of a given ARFCN+BSIC.
First, the target ARFCN+BSIC needs to be translated into a CGI-PS
(RAC+CI) address. That's done by asking the BSC through the Neighbour
Resolution Service available in osmo-bsc using the CTRL interface.
Once the CGI-PS of the target cell is known, PCU starts a RIM RAN-INFO
request against the SGSN (which will route the request as needed), and
wait for a response containing the SI bits from the target cell.
After the SI are received, the scheduler is instructed to eventually
poll a TBF for the MS originating the CCN, so that we can send the SI
encapsulated into multiple Packet Neighbor Cell Data messages on the
downlink.
One all the SI bits are sent, the scheduler is instructed to send a
Packet Cell Change Continue message.
Once the message above has been sent, the FSM autodestroys itself.
Caches are also introduced in this patch which allows for re-using
recently known translations ARFCN+BSIC -> CGI-PS and CGI-PS -> SI_INFO
respectively.
Change-Id: Id35f40d05f3e081f32fddbf1fa34cb338db452ca
2021-01-21 17:46:13 +00:00
|
|
|
ms_update_l1_meas(ms, meas);
|
|
|
|
ms_nacc_start(ms, notif);
|
|
|
|
}
|
|
|
|
|
2018-02-19 16:17:28 +00:00
|
|
|
/* Received Uplink RLC control block. */
|
2019-09-25 11:35:11 +00:00
|
|
|
int gprs_rlcmac_pdch::rcv_control_block(const uint8_t *data, uint8_t data_len,
|
2020-05-18 09:35:35 +00:00
|
|
|
uint32_t fn, struct pcu_l1_meas *meas, enum CodingScheme cs)
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
2019-09-25 11:35:11 +00:00
|
|
|
bitvec *rlc_block;
|
|
|
|
RlcMacUplink_t *ul_control_block;
|
2020-05-18 09:35:35 +00:00
|
|
|
unsigned len = mcs_max_bytes_ul(cs);
|
2020-02-03 16:18:03 +00:00
|
|
|
int rc;
|
2019-09-25 11:35:11 +00:00
|
|
|
|
|
|
|
if (!(rlc_block = bitvec_alloc(len, tall_pcu_ctx)))
|
|
|
|
return -ENOMEM;
|
|
|
|
bitvec_unpack(rlc_block, data);
|
|
|
|
ul_control_block = (RlcMacUplink_t *)talloc_zero(tall_pcu_ctx, RlcMacUplink_t);
|
|
|
|
|
2021-03-09 19:19:51 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "FN=%u +++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++\n", fn);
|
2020-03-06 01:48:24 +00:00
|
|
|
|
2020-03-26 21:33:59 +00:00
|
|
|
rc = decode_gsm_rlcmac_uplink(rlc_block, ul_control_block);
|
2020-03-06 01:48:24 +00:00
|
|
|
if (ul_control_block->u.MESSAGE_TYPE == MT_PACKET_UPLINK_DUMMY_CONTROL_BLOCK)
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_send_gsmtap_meas(bts(), PCU_GSMTAP_C_UL_DUMMY, true, trx_no(), ts_no, GSMTAP_CHANNEL_PACCH, fn, data, data_len, meas);
|
2020-03-06 01:48:24 +00:00
|
|
|
else
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_send_gsmtap_meas(bts(), PCU_GSMTAP_C_UL_CTRL, true, trx_no(), ts_no, GSMTAP_CHANNEL_PACCH, fn, data, data_len, meas);
|
2020-03-06 01:48:24 +00:00
|
|
|
|
2020-10-27 09:24:57 +00:00
|
|
|
if (rc < 0) {
|
2021-03-09 19:19:51 +00:00
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_ERROR, "FN=%u Dropping Uplink Control Block "
|
|
|
|
"with invalid content, decode failed: %d)\n", fn, rc);
|
2020-02-03 16:18:03 +00:00
|
|
|
goto free_ret;
|
|
|
|
}
|
2021-03-09 19:19:51 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "FN=%u ------------------------- RX : Uplink Control Block -------------------------\n", fn);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts(), CTR_RLC_RECV_CONTROL);
|
2018-02-19 16:17:28 +00:00
|
|
|
switch (ul_control_block->u.MESSAGE_TYPE) {
|
|
|
|
case MT_PACKET_CONTROL_ACK:
|
|
|
|
rcv_control_ack(&ul_control_block->u.Packet_Control_Acknowledgement, fn);
|
|
|
|
break;
|
|
|
|
case MT_PACKET_DOWNLINK_ACK_NACK:
|
2019-09-25 11:46:14 +00:00
|
|
|
rcv_control_dl_ack_nack(&ul_control_block->u.Packet_Downlink_Ack_Nack, fn, meas);
|
2018-02-19 16:17:28 +00:00
|
|
|
break;
|
|
|
|
case MT_EGPRS_PACKET_DOWNLINK_ACK_NACK:
|
2019-09-25 11:46:14 +00:00
|
|
|
rcv_control_egprs_dl_ack_nack(&ul_control_block->u.Egprs_Packet_Downlink_Ack_Nack, fn, meas);
|
2018-02-19 16:17:28 +00:00
|
|
|
break;
|
|
|
|
case MT_PACKET_RESOURCE_REQUEST:
|
2019-09-25 11:46:14 +00:00
|
|
|
rcv_resource_request(&ul_control_block->u.Packet_Resource_Request, fn, meas);
|
2018-02-19 16:17:28 +00:00
|
|
|
break;
|
|
|
|
case MT_PACKET_MEASUREMENT_REPORT:
|
|
|
|
rcv_measurement_report(&ul_control_block->u.Packet_Measurement_Report, fn);
|
|
|
|
break;
|
|
|
|
case MT_PACKET_UPLINK_DUMMY_CONTROL_BLOCK:
|
|
|
|
/* ignoring it. change the SI to not force sending these? */
|
|
|
|
break;
|
Introduce NACC support
A new nacc_fsm is introduced per MS object, with its partner priv
structure struct nacc_fsm_ctx, which exists and is available in the MS
object only during the duration of the NACC procedure.
The NACC context is created on an MS whenever a Pkt Cell Change
Notification is received on Uplink RLCMAC, which asks for neighbor
information of a given ARFCN+BSIC.
First, the target ARFCN+BSIC needs to be translated into a CGI-PS
(RAC+CI) address. That's done by asking the BSC through the Neighbour
Resolution Service available in osmo-bsc using the CTRL interface.
Once the CGI-PS of the target cell is known, PCU starts a RIM RAN-INFO
request against the SGSN (which will route the request as needed), and
wait for a response containing the SI bits from the target cell.
After the SI are received, the scheduler is instructed to eventually
poll a TBF for the MS originating the CCN, so that we can send the SI
encapsulated into multiple Packet Neighbor Cell Data messages on the
downlink.
One all the SI bits are sent, the scheduler is instructed to send a
Packet Cell Change Continue message.
Once the message above has been sent, the FSM autodestroys itself.
Caches are also introduced in this patch which allows for re-using
recently known translations ARFCN+BSIC -> CGI-PS and CGI-PS -> SI_INFO
respectively.
Change-Id: Id35f40d05f3e081f32fddbf1fa34cb338db452ca
2021-01-21 17:46:13 +00:00
|
|
|
case MT_PACKET_CELL_CHANGE_NOTIFICATION:
|
|
|
|
rcv_cell_change_notification(&ul_control_block->u.Packet_Cell_Change_Notification, fn, meas);
|
|
|
|
break;
|
2018-02-19 16:17:28 +00:00
|
|
|
default:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts(), CTR_DECODE_ERRORS);
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE,
|
2021-03-09 19:19:51 +00:00
|
|
|
"FN=%u RX: [PCU <- BTS] unknown control block(%d) received\n",
|
|
|
|
fn, ul_control_block->u.MESSAGE_TYPE);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
2021-03-09 16:18:12 +00:00
|
|
|
|
2020-02-03 16:18:03 +00:00
|
|
|
free_ret:
|
2018-02-19 16:17:28 +00:00
|
|
|
talloc_free(ul_control_block);
|
2019-09-25 11:35:11 +00:00
|
|
|
bitvec_free(rlc_block);
|
2020-02-03 16:18:03 +00:00
|
|
|
return rc;
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* received RLC/MAC block from L1 */
|
|
|
|
int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
|
|
|
|
struct pcu_l1_meas *meas)
|
|
|
|
{
|
2021-03-05 17:59:05 +00:00
|
|
|
/* First of all, update TDMA clock: */
|
|
|
|
bts_set_current_frame_number(trx->bts, fn);
|
|
|
|
|
2021-03-05 17:54:01 +00:00
|
|
|
/* No successfully decoded UL block was received during this FN: */
|
2021-03-09 16:18:12 +00:00
|
|
|
if (len == 0)
|
2021-03-05 17:54:01 +00:00
|
|
|
return 0;
|
|
|
|
|
2020-05-18 09:35:35 +00:00
|
|
|
enum CodingScheme cs = mcs_get_by_size_ul(len);
|
2018-02-19 16:17:28 +00:00
|
|
|
if (!cs) {
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts(), CTR_DECODE_ERRORS);
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_ERROR, "Dropping data block with invalid "
|
|
|
|
"length %d: %s\n", len, osmo_hexdump(data, len));
|
2018-02-19 16:17:28 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_add(bts(), CTR_RLC_UL_BYTES, len);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_DEBUG, "Got RLC block, coding scheme: %s, "
|
2020-05-18 09:35:35 +00:00
|
|
|
"length: %d (%d))\n", mcs_name(cs), len, mcs_used_size_ul(cs));
|
2018-02-19 16:17:28 +00:00
|
|
|
|
2019-03-25 15:32:50 +00:00
|
|
|
if (mcs_is_gprs(cs))
|
2018-02-19 16:17:28 +00:00
|
|
|
return rcv_block_gprs(data, len, fn, meas, cs);
|
|
|
|
|
2019-03-25 15:32:50 +00:00
|
|
|
if (mcs_is_edge(cs))
|
2018-02-19 16:17:28 +00:00
|
|
|
return rcv_data_block(data, len, fn, meas, cs);
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts(), CTR_DECODE_ERRORS);
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_ERROR, "Unsupported coding scheme %s\n",
|
2019-03-05 13:59:03 +00:00
|
|
|
mcs_name(cs));
|
2018-02-19 16:17:28 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief process egprs and gprs data blocks */
|
|
|
|
int gprs_rlcmac_pdch::rcv_data_block(uint8_t *data, uint8_t data_len, uint32_t fn,
|
2020-05-18 09:35:35 +00:00
|
|
|
struct pcu_l1_meas *meas, enum CodingScheme cs)
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct gprs_rlc_data_info rlc_dec;
|
|
|
|
struct gprs_rlcmac_ul_tbf *tbf;
|
2021-03-24 13:06:15 +00:00
|
|
|
struct pdch_ulc_node *node;
|
2020-05-18 09:35:35 +00:00
|
|
|
unsigned len = mcs_size_ul(cs);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
/* These are always data blocks, since EGPRS still uses CS-1 for
|
|
|
|
* control blocks (see 44.060, section 10.3, 1st par.)
|
|
|
|
*/
|
2019-03-25 15:32:50 +00:00
|
|
|
if (mcs_is_edge(cs)) {
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_send_gsmtap_meas(bts(), PCU_GSMTAP_C_UL_DATA_EGPRS, true,
|
2020-05-19 15:23:23 +00:00
|
|
|
trx_no(), ts_no, GSMTAP_CHANNEL_PDTCH, fn,
|
|
|
|
data, data_len, meas);
|
2018-02-19 16:17:28 +00:00
|
|
|
} else {
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_send_gsmtap_meas(bts(), PCU_GSMTAP_C_UL_DATA_GPRS, true,
|
2020-05-19 15:23:23 +00:00
|
|
|
trx_no(), ts_no, GSMTAP_CHANNEL_PDTCH, fn,
|
|
|
|
data, data_len, meas);
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_DEBUG, " UL data: %s\n", osmo_hexdump(data, len));
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
rc = Decoding::rlc_parse_ul_data_header(&rlc_dec, data, cs);
|
|
|
|
if (rc < 0) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_ERROR,
|
2018-02-19 16:17:28 +00:00
|
|
|
"Got %s RLC block but header parsing has failed\n",
|
2019-03-05 13:59:03 +00:00
|
|
|
mcs_name(cs));
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts(), CTR_DECODE_ERRORS);
|
2018-02-19 16:17:28 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_INFO,
|
2018-02-19 16:17:28 +00:00
|
|
|
"Got %s RLC block: "
|
|
|
|
"R=%d, SI=%d, TFI=%d, CPS=%d, RSB=%d, "
|
|
|
|
"rc=%d\n",
|
2019-03-05 13:59:03 +00:00
|
|
|
mcs_name(cs),
|
2018-02-19 16:17:28 +00:00
|
|
|
rlc_dec.r, rlc_dec.si, rlc_dec.tfi, rlc_dec.cps, rlc_dec.rsb,
|
|
|
|
rc);
|
|
|
|
|
|
|
|
/* find TBF inst from given TFI */
|
|
|
|
tbf = ul_tbf_by_tfi(rlc_dec.tfi);
|
|
|
|
if (!tbf) {
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TFI=%d\n",
|
2018-02-19 16:17:28 +00:00
|
|
|
rlc_dec.tfi);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-24 13:06:15 +00:00
|
|
|
node = pdch_ulc_get_node(ulc, fn);
|
|
|
|
if (node) {
|
|
|
|
switch (node->type) {
|
|
|
|
case PDCH_ULC_NODE_TBF_USF:
|
|
|
|
if (tbf != node->tbf_usf.ul_tbf)
|
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_NOTICE, "FN=%" PRIu32 " "
|
|
|
|
"Rx UL DATA from unexpected %s vs expected %s\n",
|
|
|
|
fn, tbf_name(tbf), tbf_name(node->tbf_usf.ul_tbf));
|
|
|
|
break;
|
|
|
|
case PDCH_ULC_NODE_TBF_POLL:
|
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_NOTICE, "FN=%" PRIu32 " "
|
|
|
|
"Rx UL DATA from unexpected %s vs expected POLL %s\n",
|
|
|
|
fn, tbf_name(tbf), tbf_name(node->tbf_poll.poll_tbf));
|
|
|
|
break;
|
|
|
|
case PDCH_ULC_NODE_SBA:
|
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_NOTICE, "FN=%" PRIu32 " "
|
|
|
|
"Rx UL DATA from unexpected %s vs expected SBA\n",
|
|
|
|
fn, tbf_name(tbf));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pdch_ulc_release_node(ulc, node);
|
|
|
|
} else {
|
|
|
|
LOGPDCH(this, DRLCMACUL, LOGL_NOTICE, "FN=%" PRIu32 " "
|
|
|
|
"Rx UL DATA from unexpected %s\n", fn, tbf_name(tbf));
|
|
|
|
}
|
|
|
|
|
2018-02-19 16:17:28 +00:00
|
|
|
/* Reset N3101 counter: */
|
2018-02-20 17:16:11 +00:00
|
|
|
tbf->n_reset(N3101);
|
2018-02-19 16:17:28 +00:00
|
|
|
|
|
|
|
return tbf->rcv_data_block_acknowledged(&rlc_dec, data, meas);
|
|
|
|
}
|
|
|
|
|
|
|
|
int gprs_rlcmac_pdch::rcv_block_gprs(uint8_t *data, uint8_t data_len, uint32_t fn,
|
2020-05-18 09:35:35 +00:00
|
|
|
struct pcu_l1_meas *meas, enum CodingScheme cs)
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
|
|
|
unsigned payload = data[0] >> 6;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
switch (payload) {
|
|
|
|
case GPRS_RLCMAC_DATA_BLOCK:
|
|
|
|
rc = rcv_data_block(data, data_len, fn, meas, cs);
|
|
|
|
break;
|
|
|
|
case GPRS_RLCMAC_CONTROL_BLOCK:
|
2019-09-25 11:46:14 +00:00
|
|
|
rc = rcv_control_block(data, data_len, fn, meas, cs);
|
2018-02-19 16:17:28 +00:00
|
|
|
break;
|
|
|
|
case GPRS_RLCMAC_CONTROL_BLOCK_OPT:
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "GPRS_RLCMAC_CONTROL_BLOCK_OPT block payload is not supported.\n");
|
2018-02-19 16:17:28 +00:00
|
|
|
break;
|
|
|
|
default:
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "Unknown RLCMAC block payload(%u).\n", payload);
|
2018-02-19 16:17:28 +00:00
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi(
|
|
|
|
LListHead<gprs_rlcmac_tbf> *tbf_list, uint8_t tfi,
|
|
|
|
enum gprs_rlcmac_tbf_direction dir)
|
|
|
|
{
|
|
|
|
gprs_rlcmac_tbf *tbf;
|
|
|
|
LListHead<gprs_rlcmac_tbf> *pos;
|
|
|
|
|
|
|
|
llist_for_each(pos, tbf_list) {
|
|
|
|
tbf = pos->entry();
|
|
|
|
if (tbf->tfi() != tfi)
|
|
|
|
continue;
|
|
|
|
if (!tbf->pdch[ts_no])
|
|
|
|
continue;
|
|
|
|
return tbf;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gprs_rlcmac_ul_tbf *gprs_rlcmac_pdch::ul_tbf_by_tfi(uint8_t tfi)
|
|
|
|
{
|
|
|
|
return as_ul_tbf(tbf_by_tfi(tfi, GPRS_RLCMAC_UL_TBF));
|
|
|
|
}
|
|
|
|
|
|
|
|
gprs_rlcmac_dl_tbf *gprs_rlcmac_pdch::dl_tbf_by_tfi(uint8_t tfi)
|
|
|
|
{
|
|
|
|
return as_dl_tbf(tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lookup TBF Entity (by TFI) */
|
|
|
|
gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_by_tfi(uint8_t tfi,
|
|
|
|
enum gprs_rlcmac_tbf_direction dir)
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_tbf *tbf;
|
|
|
|
|
|
|
|
if (tfi >= 32)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
tbf = m_tbfs[dir][tfi];
|
|
|
|
|
2021-04-22 19:03:33 +00:00
|
|
|
return tbf;
|
2018-02-19 16:17:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::attach_tbf(gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
gprs_rlcmac_ul_tbf *ul_tbf;
|
|
|
|
|
|
|
|
if (m_tbfs[tbf->direction][tbf->tfi()])
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_ERROR,
|
2018-02-19 16:17:28 +00:00
|
|
|
"%s has not been detached, overwriting it\n",
|
|
|
|
m_tbfs[tbf->direction][tbf->tfi()]->name());
|
|
|
|
|
|
|
|
m_num_tbfs[tbf->direction] += 1;
|
2021-08-23 14:58:04 +00:00
|
|
|
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
|
|
|
|
ul_tbf = as_ul_tbf(tbf);
|
2018-02-19 16:17:28 +00:00
|
|
|
m_assigned_usf |= 1 << ul_tbf->m_usf[ts_no];
|
|
|
|
}
|
|
|
|
m_assigned_tfi[tbf->direction] |= 1UL << tbf->tfi();
|
|
|
|
m_tbfs[tbf->direction][tbf->tfi()] = tbf;
|
|
|
|
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_INFO, "Attaching %s, %d TBFs, "
|
2018-02-19 16:17:28 +00:00
|
|
|
"USFs = %02x, TFIs = %08x.\n",
|
2021-02-25 16:49:30 +00:00
|
|
|
tbf->name(), m_num_tbfs[tbf->direction],
|
2018-02-19 16:17:28 +00:00
|
|
|
m_assigned_usf, m_assigned_tfi[tbf->direction]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::detach_tbf(gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
gprs_rlcmac_ul_tbf *ul_tbf;
|
|
|
|
|
|
|
|
OSMO_ASSERT(m_num_tbfs[tbf->direction] > 0);
|
|
|
|
|
|
|
|
m_num_tbfs[tbf->direction] -= 1;
|
2021-08-23 14:58:04 +00:00
|
|
|
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
|
|
|
|
ul_tbf = as_ul_tbf(tbf);
|
2018-02-19 16:17:28 +00:00
|
|
|
m_assigned_usf &= ~(1 << ul_tbf->m_usf[ts_no]);
|
|
|
|
}
|
|
|
|
m_assigned_tfi[tbf->direction] &= ~(1UL << tbf->tfi());
|
|
|
|
m_tbfs[tbf->direction][tbf->tfi()] = NULL;
|
|
|
|
|
2021-03-09 16:18:12 +00:00
|
|
|
pdch_ulc_release_tbf(ulc, tbf);
|
|
|
|
|
2021-02-25 16:49:30 +00:00
|
|
|
LOGPDCH(this, DRLCMAC, LOGL_INFO, "Detaching %s, %d TBFs, "
|
2018-02-19 16:17:28 +00:00
|
|
|
"USFs = %02x, TFIs = %08x.\n",
|
2021-02-25 16:49:30 +00:00
|
|
|
tbf->name(), m_num_tbfs[tbf->direction],
|
2018-02-19 16:17:28 +00:00
|
|
|
m_assigned_usf, m_assigned_tfi[tbf->direction]);
|
|
|
|
}
|
|
|
|
|
2020-11-16 16:35:10 +00:00
|
|
|
bool gprs_rlcmac_pdch::has_gprs_only_tbf_attached() const
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
unsigned int j;
|
|
|
|
for (i = 0; i < sizeof(m_assigned_tfi[0]); i++) {
|
|
|
|
for (j = 0; j < 2; j++) {
|
|
|
|
if (m_assigned_tfi[j] & (1UL << i)) {
|
|
|
|
gprs_rlcmac_tbf *tbf = m_tbfs[j][i];
|
|
|
|
if (!tbf->is_egprs_enabled())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-02-19 16:17:28 +00:00
|
|
|
void gprs_rlcmac_pdch::reserve(enum gprs_rlcmac_tbf_direction dir)
|
|
|
|
{
|
|
|
|
m_num_reserved[dir] += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::unreserve(enum gprs_rlcmac_tbf_direction dir)
|
|
|
|
{
|
|
|
|
OSMO_ASSERT(m_num_reserved[dir] > 0);
|
|
|
|
m_num_reserved[dir] -= 1;
|
|
|
|
}
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
inline struct gprs_rlcmac_bts *gprs_rlcmac_pdch::bts() const
|
2018-02-19 16:17:28 +00:00
|
|
|
{
|
|
|
|
return trx->bts;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t gprs_rlcmac_pdch::trx_no() const
|
|
|
|
{
|
|
|
|
return trx->trx_no;
|
|
|
|
}
|
|
|
|
|
2019-10-05 14:57:14 +00:00
|
|
|
uint8_t gprs_rlcmac_pdch::reserve_tai(uint8_t ta)
|
|
|
|
{
|
|
|
|
uint8_t tai;
|
|
|
|
|
|
|
|
for (tai = 0; tai < PTCCH_TAI_NUM; tai++) {
|
|
|
|
if (ptcch_msg[tai] == PTCCH_TAI_FREE) {
|
|
|
|
ptcch_msg[tai] = ta;
|
|
|
|
return tai;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Special case: no free TAI available */
|
|
|
|
return PTCCH_TAI_FREE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::release_tai(uint8_t tai)
|
|
|
|
{
|
|
|
|
OSMO_ASSERT(tai < PTCCH_TAI_NUM);
|
|
|
|
ptcch_msg[tai] = PTCCH_TAI_FREE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_pdch::update_ta(uint8_t tai, uint8_t ta)
|
|
|
|
{
|
|
|
|
OSMO_ASSERT(tai < PTCCH_TAI_NUM);
|
|
|
|
ptcch_msg[tai] = ta;
|
|
|
|
}
|
2021-01-18 16:53:29 +00:00
|
|
|
|
|
|
|
void pdch_free_all_tbf(struct gprs_rlcmac_pdch *pdch)
|
|
|
|
{
|
|
|
|
for (uint8_t tfi = 0; tfi < 32; tfi++) {
|
|
|
|
struct gprs_rlcmac_tbf *tbf;
|
|
|
|
|
|
|
|
tbf = pdch->ul_tbf_by_tfi(tfi);
|
|
|
|
if (tbf)
|
|
|
|
tbf_free(tbf);
|
|
|
|
tbf = pdch->dl_tbf_by_tfi(tfi);
|
|
|
|
if (tbf)
|
|
|
|
tbf_free(tbf);
|
|
|
|
}
|
|
|
|
}
|
2021-01-18 16:54:30 +00:00
|
|
|
|
2021-06-30 14:03:06 +00:00
|
|
|
void pdch_disable(struct gprs_rlcmac_pdch *pdch)
|
|
|
|
{
|
2021-01-18 16:54:30 +00:00
|
|
|
pdch->disable();
|
|
|
|
}
|
2021-06-30 14:03:06 +00:00
|
|
|
|
|
|
|
bool pdch_is_enabled(const struct gprs_rlcmac_pdch *pdch)
|
|
|
|
{
|
|
|
|
return pdch->is_enabled();
|
|
|
|
}
|