2014-08-08 10:14:12 +00:00
|
|
|
/* Copied from tbf.cpp
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Ivan Klyuchnikov
|
|
|
|
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
* Copyright (C) 2013 by Holger Hans Peter Freyther
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <bts.h>
|
|
|
|
#include <tbf.h>
|
2019-09-25 15:47:02 +00:00
|
|
|
#include <tbf_ul.h>
|
2014-08-08 10:14:12 +00:00
|
|
|
#include <rlc.h>
|
|
|
|
#include <encoding.h>
|
|
|
|
#include <gprs_rlcmac.h>
|
|
|
|
#include <gprs_debug.h>
|
|
|
|
#include <gprs_bssgp_pcu.h>
|
|
|
|
#include <decoding.h>
|
2015-06-08 09:05:45 +00:00
|
|
|
#include <pcu_l1_if.h>
|
2018-01-26 12:31:42 +00:00
|
|
|
#include <gprs_ms.h>
|
|
|
|
#include <llc.h>
|
2017-01-16 10:11:21 +00:00
|
|
|
#include "pcu_utils.h"
|
|
|
|
|
2014-08-08 10:14:12 +00:00
|
|
|
extern "C" {
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/talloc.h>
|
2018-01-26 12:31:42 +00:00
|
|
|
#include <osmocom/core/bitvec.h>
|
|
|
|
#include <osmocom/core/logging.h>
|
|
|
|
#include <osmocom/core/rate_ctr.h>
|
2020-10-23 20:30:04 +00:00
|
|
|
#include <osmocom/core/stats.h>
|
2018-01-26 12:31:42 +00:00
|
|
|
#include <osmocom/core/utils.h>
|
|
|
|
#include <osmocom/gprs/gprs_bssgp_bss.h>
|
|
|
|
#include <osmocom/gprs/protocol/gsm_08_18.h>
|
|
|
|
#include <osmocom/gsm/tlv.h>
|
2019-03-05 13:59:03 +00:00
|
|
|
#include "coding_scheme.h"
|
2014-08-08 10:14:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
/* After receiving these frames, we send ack/nack. */
|
|
|
|
#define SEND_ACK_AFTER_FRAMES 20
|
|
|
|
|
|
|
|
extern void *tall_pcu_ctx;
|
|
|
|
|
2020-10-23 20:30:04 +00:00
|
|
|
static const struct rate_ctr_desc tbf_ul_gprs_ctr_description[] = {
|
|
|
|
{ "gprs:uplink:cs1", "CS1 " },
|
|
|
|
{ "gprs:uplink:cs2", "CS2 " },
|
|
|
|
{ "gprs:uplink:cs3", "CS3 " },
|
|
|
|
{ "gprs:uplink:cs4", "CS4 " },
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct rate_ctr_desc tbf_ul_egprs_ctr_description[] = {
|
|
|
|
{ "egprs:uplink:mcs1", "MCS1 " },
|
|
|
|
{ "egprs:uplink:mcs2", "MCS2 " },
|
|
|
|
{ "egprs:uplink:mcs3", "MCS3 " },
|
|
|
|
{ "egprs:uplink:mcs4", "MCS4 " },
|
|
|
|
{ "egprs:uplink:mcs5", "MCS5 " },
|
|
|
|
{ "egprs:uplink:mcs6", "MCS6 " },
|
|
|
|
{ "egprs:uplink:mcs7", "MCS7 " },
|
|
|
|
{ "egprs:uplink:mcs8", "MCS8 " },
|
|
|
|
{ "egprs:uplink:mcs9", "MCS9 " },
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct rate_ctr_group_desc tbf_ul_gprs_ctrg_desc = {
|
|
|
|
"tbf:gprs",
|
|
|
|
"Data Blocks",
|
|
|
|
OSMO_STATS_CLASS_SUBSCRIBER,
|
|
|
|
ARRAY_SIZE(tbf_ul_gprs_ctr_description),
|
|
|
|
tbf_ul_gprs_ctr_description,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct rate_ctr_group_desc tbf_ul_egprs_ctrg_desc = {
|
|
|
|
"tbf:egprs",
|
|
|
|
"Data Blocks",
|
|
|
|
OSMO_STATS_CLASS_SUBSCRIBER,
|
|
|
|
ARRAY_SIZE(tbf_ul_egprs_ctr_description),
|
|
|
|
tbf_ul_egprs_ctr_description,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int ul_tbf_dtor(struct gprs_rlcmac_ul_tbf *tbf)
|
|
|
|
{
|
|
|
|
tbf->~gprs_rlcmac_ul_tbf();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-26 14:48:34 +00:00
|
|
|
/* Generic function to alloc a UL TBF, later configured to be assigned either over CCCH or PACCH */
|
2020-10-23 20:30:04 +00:00
|
|
|
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts, GprsMs *ms, int8_t use_trx, bool single_slot)
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_ul_tbf *tbf;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
OSMO_ASSERT(ms != NULL);
|
|
|
|
|
2021-02-25 16:57:37 +00:00
|
|
|
LOGPMS(ms, DTBF, LOGL_DEBUG, "********** UL-TBF starts here **********\n");
|
|
|
|
LOGPMS(ms, DTBF, LOGL_INFO, "Allocating UL TBF\n");
|
2020-10-23 20:30:04 +00:00
|
|
|
|
|
|
|
tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
|
|
|
|
if (!tbf)
|
|
|
|
return NULL;
|
|
|
|
talloc_set_destructor(tbf, ul_tbf_dtor);
|
2021-01-14 15:48:38 +00:00
|
|
|
new (tbf) gprs_rlcmac_ul_tbf(bts, ms);
|
2020-10-23 20:30:04 +00:00
|
|
|
|
|
|
|
rc = tbf->setup(use_trx, single_slot);
|
|
|
|
|
|
|
|
/* if no resource */
|
|
|
|
if (rc < 0) {
|
|
|
|
talloc_free(tbf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tbf->is_egprs_enabled())
|
|
|
|
tbf->set_window_size();
|
|
|
|
|
|
|
|
tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(tbf,
|
|
|
|
&tbf_ul_egprs_ctrg_desc, tbf->m_ctrs->idx);
|
|
|
|
tbf->m_ul_gprs_ctrs = rate_ctr_group_alloc(tbf,
|
|
|
|
&tbf_ul_gprs_ctrg_desc, tbf->m_ctrs->idx);
|
|
|
|
if (!tbf->m_ul_egprs_ctrs || !tbf->m_ul_gprs_ctrs) {
|
|
|
|
LOGPTBF(tbf, LOGL_ERROR, "Couldn't allocate TBF UL counters\n");
|
|
|
|
talloc_free(tbf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-05-13 16:39:36 +00:00
|
|
|
llist_add_tail(tbf_trx_list(tbf), &tbf->trx->ul_tbfs);
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_UL_ALLOCATED);
|
2020-10-23 20:30:04 +00:00
|
|
|
|
|
|
|
return tbf;
|
|
|
|
}
|
|
|
|
|
2021-04-26 14:48:34 +00:00
|
|
|
/* Alloc a UL TBF to be assigned over PACCH */
|
2021-05-10 15:10:37 +00:00
|
|
|
gprs_rlcmac_ul_tbf *tbf_alloc_ul_pacch(struct gprs_rlcmac_bts *bts, GprsMs *ms, int8_t use_trx,
|
2020-10-23 20:30:04 +00:00
|
|
|
uint32_t tlli)
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_ul_tbf *tbf;
|
|
|
|
|
|
|
|
tbf = tbf_alloc_ul_tbf(bts, ms, use_trx, false);
|
|
|
|
if (!tbf) {
|
2021-02-25 16:57:37 +00:00
|
|
|
LOGPMS(ms, DTBF, LOGL_NOTICE, "No PDCH resource\n");
|
2021-04-26 14:48:34 +00:00
|
|
|
/* Caller will most probably send a Imm Ass Reject after return */
|
2020-10-23 20:30:04 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
tbf->m_contention_resolution_done = 1;
|
|
|
|
TBF_SET_ASS_ON(tbf, GPRS_RLCMAC_FLAG_PACCH, false);
|
|
|
|
tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);
|
|
|
|
OSMO_ASSERT(tbf->ms());
|
|
|
|
|
|
|
|
return tbf;
|
|
|
|
}
|
|
|
|
|
2021-05-10 15:21:03 +00:00
|
|
|
/* Alloc a UL TBF to be assigned over CCCH */
|
|
|
|
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_ccch(struct gprs_rlcmac_bts *bts, struct GprsMs *ms)
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_ul_tbf *tbf;
|
|
|
|
|
|
|
|
tbf = tbf_alloc_ul_tbf(bts, ms, -1, true);
|
|
|
|
if (!tbf) {
|
|
|
|
LOGP(DTBF, LOGL_NOTICE, "No PDCH resource for Uplink TBF\n");
|
|
|
|
/* Caller will most probably send a Imm Ass Reject after return */
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-05-14 10:50:46 +00:00
|
|
|
TBF_SET_STATE(tbf, TBF_ST_FLOW);
|
2021-05-10 15:21:03 +00:00
|
|
|
TBF_ASS_TYPE_SET(tbf, GPRS_RLCMAC_FLAG_CCCH);
|
2021-05-10 16:54:52 +00:00
|
|
|
tbf->contention_resolution_start();
|
2021-05-10 15:21:03 +00:00
|
|
|
OSMO_ASSERT(tbf->ms());
|
|
|
|
|
|
|
|
return tbf;
|
|
|
|
}
|
|
|
|
|
2021-04-26 14:48:34 +00:00
|
|
|
/* Create a temporary dummy TBF to Tx a ImmAssReject if allocating a new one during
|
|
|
|
* packet resource Request failed. This is similar as tbf_alloc_ul() but without
|
|
|
|
* calling tbf->setup() (in charge of TFI/USF allocation), and reusing resources
|
|
|
|
* from Packet Resource Request we received. See TS 44.060 sec 7.1.3.2.1 */
|
2020-10-23 20:30:04 +00:00
|
|
|
struct gprs_rlcmac_ul_tbf *handle_tbf_reject(struct gprs_rlcmac_bts *bts,
|
2021-04-26 14:48:34 +00:00
|
|
|
GprsMs *ms, uint8_t trx_no, uint8_t ts)
|
2020-10-23 20:30:04 +00:00
|
|
|
{
|
|
|
|
struct gprs_rlcmac_ul_tbf *ul_tbf = NULL;
|
|
|
|
struct gprs_rlcmac_trx *trx = &bts->trx[trx_no];
|
2021-04-26 14:48:34 +00:00
|
|
|
OSMO_ASSERT(ms);
|
2020-10-23 20:30:04 +00:00
|
|
|
|
|
|
|
ul_tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
|
|
|
|
if (!ul_tbf)
|
|
|
|
return ul_tbf;
|
|
|
|
talloc_set_destructor(ul_tbf, ul_tbf_dtor);
|
2021-01-14 15:48:38 +00:00
|
|
|
new (ul_tbf) gprs_rlcmac_ul_tbf(bts, ms);
|
2020-10-23 20:30:04 +00:00
|
|
|
|
|
|
|
ul_tbf->control_ts = ts;
|
|
|
|
ul_tbf->trx = trx;
|
|
|
|
ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, next_tbf_ctr_group_id++);
|
|
|
|
ul_tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(ul_tbf,
|
|
|
|
&tbf_ul_egprs_ctrg_desc,
|
|
|
|
ul_tbf->m_ctrs->idx);
|
|
|
|
ul_tbf->m_ul_gprs_ctrs = rate_ctr_group_alloc(ul_tbf,
|
|
|
|
&tbf_ul_gprs_ctrg_desc,
|
|
|
|
ul_tbf->m_ctrs->idx);
|
|
|
|
if (!ul_tbf->m_ctrs || !ul_tbf->m_ul_egprs_ctrs || !ul_tbf->m_ul_gprs_ctrs) {
|
|
|
|
LOGPTBF(ul_tbf, LOGL_ERROR, "Cound not allocate TBF UL rate counters\n");
|
|
|
|
talloc_free(ul_tbf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-04-26 14:48:34 +00:00
|
|
|
ms_attach_tbf(ms, ul_tbf);
|
2021-05-13 16:39:36 +00:00
|
|
|
llist_add(tbf_trx_list((struct gprs_rlcmac_tbf *)ul_tbf), &trx->ul_tbfs);
|
2021-04-26 14:48:34 +00:00
|
|
|
bts_do_rate_ctr_inc(ul_tbf->bts, CTR_TBF_UL_ALLOCATED);
|
|
|
|
TBF_SET_ASS_ON(ul_tbf, GPRS_RLCMAC_FLAG_PACCH, false);
|
|
|
|
TBF_SET_ASS_STATE_UL(ul_tbf, GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ);
|
|
|
|
|
2020-10-23 20:30:04 +00:00
|
|
|
return ul_tbf;
|
|
|
|
}
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
gprs_rlcmac_ul_tbf::gprs_rlcmac_ul_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms) :
|
2020-10-23 16:41:40 +00:00
|
|
|
gprs_rlcmac_tbf(bts_, ms, GPRS_RLCMAC_UL_TBF),
|
2019-09-26 12:41:18 +00:00
|
|
|
m_rx_counter(0),
|
|
|
|
m_contention_resolution_done(0),
|
|
|
|
m_final_ack_sent(0),
|
|
|
|
m_ul_gprs_ctrs(NULL),
|
|
|
|
m_ul_egprs_ctrs(NULL)
|
|
|
|
{
|
2021-03-24 12:14:09 +00:00
|
|
|
memset(&m_usf, USF_INVALID, sizeof(m_usf));
|
2019-09-26 12:41:18 +00:00
|
|
|
}
|
|
|
|
|
2015-12-14 12:36:13 +00:00
|
|
|
/*
|
|
|
|
* Store received block data in LLC message(s) and forward to SGSN
|
|
|
|
* if complete.
|
|
|
|
*/
|
|
|
|
int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
|
|
|
|
{
|
|
|
|
const uint8_t *data = _data->block;
|
|
|
|
uint8_t len = _data->len;
|
2016-01-07 17:59:28 +00:00
|
|
|
const struct gprs_rlc_data_block_info *rdbi = &_data->block_info;
|
2020-05-18 09:35:35 +00:00
|
|
|
enum CodingScheme cs = _data->cs_last;
|
2015-12-14 12:36:13 +00:00
|
|
|
|
|
|
|
Decoding::RlcData frames[16], *frame;
|
|
|
|
int i, num_frames = 0;
|
|
|
|
uint32_t dummy_tlli;
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "Assembling frames: (len=%d)\n", len);
|
2015-12-14 12:36:13 +00:00
|
|
|
|
|
|
|
num_frames = Decoding::rlc_data_from_ul_data(
|
2016-05-24 12:45:41 +00:00
|
|
|
rdbi, cs, data, &(frames[0]), ARRAY_SIZE(frames),
|
2015-12-14 12:36:13 +00:00
|
|
|
&dummy_tlli);
|
|
|
|
|
|
|
|
/* create LLC frames */
|
|
|
|
for (i = 0; i < num_frames; i++) {
|
|
|
|
frame = frames + i;
|
|
|
|
|
2016-09-15 11:54:49 +00:00
|
|
|
if (frame->length) {
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_add(bts, CTR_RLC_UL_PAYLOAD_BYTES, frame->length);
|
2016-05-21 17:45:23 +00:00
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "Frame %d "
|
2016-09-15 11:54:49 +00:00
|
|
|
"starts at offset %d, "
|
|
|
|
"length=%d, is_complete=%d\n",
|
|
|
|
i + 1, frame->offset, frame->length,
|
|
|
|
frame->is_complete);
|
2015-12-14 12:36:13 +00:00
|
|
|
|
2016-09-15 11:54:49 +00:00
|
|
|
m_llc.append_frame(data + frame->offset, frame->length);
|
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
|
|
|
llc_consume(&m_llc, frame->length);
|
2016-09-15 11:54:49 +00:00
|
|
|
}
|
2015-12-14 12:36:13 +00:00
|
|
|
|
|
|
|
if (frame->is_complete) {
|
|
|
|
/* send frame to SGSN */
|
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
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "complete UL frame len=%d\n", llc_frame_length(&m_llc));
|
2015-12-14 12:36:13 +00:00
|
|
|
snd_ul_ud();
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_add(bts, CTR_LLC_UL_BYTES, llc_frame_length(&m_llc));
|
2015-12-14 12:36:13 +00:00
|
|
|
m_llc.reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-07 12:29:36 +00:00
|
|
|
bool gprs_rlcmac_ul_tbf::ctrl_ack_to_toggle()
|
|
|
|
{
|
2018-01-02 13:17:04 +00:00
|
|
|
if (check_n_clear(GPRS_RLCMAC_FLAG_TO_UL_ACK))
|
2017-07-07 12:29:36 +00:00
|
|
|
return true; /* GPRS_RLCMAC_FLAG_TO_UL_ACK was set, now cleared */
|
|
|
|
|
|
|
|
state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ACK);
|
|
|
|
return false; /* GPRS_RLCMAC_FLAG_TO_UL_ACK was unset, now set */
|
|
|
|
}
|
|
|
|
|
2021-03-29 16:15:30 +00:00
|
|
|
bool gprs_rlcmac_ul_tbf::handle_ctrl_ack(enum pdch_ulc_tbf_poll_reason reason)
|
2017-07-07 12:29:36 +00:00
|
|
|
{
|
|
|
|
/* check if this control ack belongs to packet uplink ack */
|
2021-03-29 16:15:30 +00:00
|
|
|
if (reason == PDCH_ULC_POLL_UL_ACK && ul_ack_state_is(GPRS_RLCMAC_UL_ACK_WAIT_ACK)) {
|
2018-01-23 19:16:23 +00:00
|
|
|
TBF_SET_ACK_STATE(this, GPRS_RLCMAC_UL_ACK_NONE);
|
2017-07-07 12:29:36 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2014-08-08 10:14:12 +00:00
|
|
|
|
2021-05-10 16:54:52 +00:00
|
|
|
void gprs_rlcmac_ul_tbf::contention_resolution_start()
|
|
|
|
{
|
|
|
|
/* 3GPP TS 44.018 sec 11.1.2 Timers on the network side: "This timer is
|
|
|
|
* started when a temporary block flow is allocated with an IMMEDIATE
|
|
|
|
* ASSIGNMENT or an IMMEDIATE PACKET ASSIGNMENT or an EC IMMEDIATE
|
|
|
|
* ASSIGNMENT TYPE 1 message during a packet access procedure. It is
|
|
|
|
* stopped when the mobile station has correctly seized the temporary
|
|
|
|
* block flow."
|
|
|
|
* In our code base, it means we want to do contention resolution
|
|
|
|
* timeout only for one-phase packet access, since two-phase is handled
|
|
|
|
* through SBA structs, which are freed by the PDCH UL Controller if the
|
|
|
|
* single allocated block is lost. */
|
|
|
|
T_START(this, T3141, 3141, "Contention resolution (UL-TBF, CCCH)", true);
|
|
|
|
}
|
|
|
|
void gprs_rlcmac_ul_tbf::contention_resolution_success()
|
|
|
|
{
|
|
|
|
if (m_contention_resolution_done)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* 3GPP TS 44.060 sec 7a.2.1 Contention Resolution */
|
|
|
|
/* 3GPP TS 44.018 3.5.2.1.4 Packet access completion: The one phase
|
|
|
|
packet access procedure is completed at a successful contention
|
|
|
|
resolution. The mobile station has entered the packet transfer mode.
|
|
|
|
Timer T3141 is stopped on the network side */
|
|
|
|
t_stop(T3141, "Contention resolution success (UL-TBF, CCCH)");
|
|
|
|
|
|
|
|
/* now we must set this flag, so we are allowed to assign downlink
|
|
|
|
* TBF on PACCH. it is only allowed when TLLI is acknowledged. */
|
|
|
|
m_contention_resolution_done = 1;
|
|
|
|
}
|
|
|
|
|
2016-01-22 16:25:38 +00:00
|
|
|
struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn, uint8_t ts)
|
2014-08-08 10:14:12 +00:00
|
|
|
{
|
2021-05-14 10:50:46 +00:00
|
|
|
int final = (state_is(TBF_ST_FINISHED));
|
2014-08-08 10:14:12 +00:00
|
|
|
struct msgb *msg;
|
2016-01-26 20:46:26 +00:00
|
|
|
int rc;
|
|
|
|
unsigned int rrbp = 0;
|
|
|
|
uint32_t new_poll_fn = 0;
|
2014-08-08 10:14:12 +00:00
|
|
|
|
|
|
|
if (final) {
|
2021-03-29 14:16:27 +00:00
|
|
|
if (ul_ack_state_is(GPRS_RLCMAC_UL_ACK_WAIT_ACK)) {
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Polling is already scheduled, so we must wait for the final uplink ack...\n");
|
2014-08-08 10:14:12 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-01-26 20:46:26 +00:00
|
|
|
|
|
|
|
rc = check_polling(fn, ts, &new_poll_fn, &rrbp);
|
|
|
|
if (rc < 0)
|
2014-08-08 10:14:12 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = msgb_alloc(23, "rlcmac_ul_ack");
|
|
|
|
if (!msg)
|
|
|
|
return NULL;
|
2017-02-04 02:10:08 +00:00
|
|
|
bitvec *ack_vec = bitvec_alloc(23, tall_pcu_ctx);
|
2014-08-08 10:14:12 +00:00
|
|
|
if (!ack_vec) {
|
|
|
|
msgb_free(msg);
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-02-18 19:42:42 +00:00
|
|
|
bitvec_unhex(ack_vec, DUMMY_VEC);
|
2019-06-16 13:25:30 +00:00
|
|
|
Encoding::write_packet_uplink_ack(ack_vec, this, final, rrbp);
|
2014-08-08 10:14:12 +00:00
|
|
|
bitvec_pack(ack_vec, msgb_put(msg, 23));
|
|
|
|
bitvec_free(ack_vec);
|
|
|
|
|
2021-05-10 16:54:52 +00:00
|
|
|
/* TS 44.060 7a.2.1.1: "The contention resolution is completed on
|
|
|
|
* the network side when the network receives an RLC data block that
|
|
|
|
* comprises the TLLI value that identifies the mobile station and the
|
|
|
|
* TFI value associated with the TBF."
|
|
|
|
* However, it's handier for us to mark contention resolution success
|
|
|
|
* here since according to spec upon rx UL ACK is the time at which MS
|
|
|
|
* realizes contention resolution succeeds. */
|
2021-05-11 10:55:31 +00:00
|
|
|
if (is_tlli_valid())
|
2021-05-10 16:54:52 +00:00
|
|
|
contention_resolution_success();
|
2014-08-08 10:14:12 +00:00
|
|
|
|
|
|
|
if (final) {
|
2021-03-29 16:15:30 +00:00
|
|
|
set_polling(new_poll_fn, ts, PDCH_ULC_POLL_UL_ACK);
|
2014-08-08 10:14:12 +00:00
|
|
|
/* waiting for final acknowledge */
|
|
|
|
m_final_ack_sent = 1;
|
|
|
|
} else
|
2018-01-23 19:16:23 +00:00
|
|
|
TBF_SET_ACK_STATE(this, GPRS_RLCMAC_UL_ACK_NONE);
|
2014-08-08 10:14:12 +00:00
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2016-05-24 12:40:03 +00:00
|
|
|
/*! \brief receive data from PDCH/L1 */
|
2015-12-14 12:36:13 +00:00
|
|
|
int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
|
2016-01-07 17:59:28 +00:00
|
|
|
const struct gprs_rlc_data_info *rlc,
|
2016-01-11 08:58:11 +00:00
|
|
|
uint8_t *data, struct pcu_l1_meas *meas)
|
2015-12-14 12:36:13 +00:00
|
|
|
{
|
2020-05-15 14:57:48 +00:00
|
|
|
const struct gprs_rlc_data_block_info *rdbi;
|
|
|
|
struct gprs_rlc_data *block;
|
|
|
|
|
2015-12-14 12:36:13 +00:00
|
|
|
int8_t rssi = meas->have_rssi ? meas->rssi : 0;
|
|
|
|
|
|
|
|
const uint16_t ws = m_window.ws();
|
|
|
|
|
|
|
|
this->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA);
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "UL DATA TFI=%d received (V(Q)=%d .. "
|
2015-12-14 12:36:13 +00:00
|
|
|
"V(R)=%d)\n", rlc->tfi, this->m_window.v_q(),
|
|
|
|
this->m_window.v_r());
|
|
|
|
|
|
|
|
/* process RSSI */
|
|
|
|
gprs_rlcmac_rssi(this, rssi);
|
|
|
|
|
|
|
|
/* store measurement values */
|
2021-05-11 12:23:51 +00:00
|
|
|
ms_update_l1_meas(ms(), meas);
|
2015-12-14 12:36:13 +00:00
|
|
|
|
TLLI 0x00000000 is a valid TLLI, use 0xffffffff instead
The assumption that TLLI 0x00000000 is invalid and can be used
as the initializer is wrong. Similar to TMSI, 0x00000000 is a
perfectly valid value, while 0xffffffff is reserved - use it.
According to 3GPP TS 23.003, section 2.4, a TMSI/P-TMSI with
all 32 bits equal to 1 is special and shall not be allocated by
the network. The reason is that it must be stored on the SIM,
where 'ff'O represents the erased state. According to section
2.6 of the same document, a local/foreign TLLI is derived from
P-TMSI, so the same rule applies to TLLI.
I manually checked and corrected all occurances of 'tlli' in the
code. The test expectations have been adjusted with this command:
$ find tests/ -name "*.err" | xargs sed -i "s/0x00000000/0xffffffff/g"
so there should be no behavior change. The only exception is
the 'TypesTest', where TLLI 0xffffffff is being encoded and
expected in the hexdump, so I regenerated the test output.
Change-Id: Ie89fab75ecc1d8b5e238d3ff214ea7ac830b68b5
Related: OS#4844
2020-11-08 06:27:35 +00:00
|
|
|
uint32_t new_tlli = GSM_RESERVED_TMSI;
|
2015-12-14 12:36:13 +00:00
|
|
|
unsigned int block_idx;
|
|
|
|
|
|
|
|
/* Increment RX-counter */
|
|
|
|
this->m_rx_counter++;
|
2016-11-10 12:46:30 +00:00
|
|
|
update_coding_scheme_counter_ul(rlc->cs);
|
2015-12-14 12:36:13 +00:00
|
|
|
/* Loop over num_blocks */
|
|
|
|
for (block_idx = 0; block_idx < rlc->num_data_blocks; block_idx++) {
|
|
|
|
int num_chunks;
|
|
|
|
uint8_t *rlc_data;
|
2020-05-15 14:57:48 +00:00
|
|
|
rdbi = &rlc->block_info[block_idx];
|
2015-12-14 12:36:13 +00:00
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Got %s RLC data block: CV=%d, BSN=%d, SPB=%d, PI=%d, E=%d, TI=%d, bitoffs=%d\n",
|
2019-03-05 13:59:03 +00:00
|
|
|
mcs_name(rlc->cs),
|
2018-01-19 17:22:25 +00:00
|
|
|
rdbi->cv, rdbi->bsn, rdbi->spb,
|
|
|
|
rdbi->pi, rdbi->e, rdbi->ti,
|
|
|
|
rlc->data_offs_bits[block_idx]);
|
2015-12-14 12:36:13 +00:00
|
|
|
|
|
|
|
/* Check whether the block needs to be decoded */
|
|
|
|
|
|
|
|
if (!m_window.is_in_window(rdbi->bsn)) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "BSN %d out of window %d..%d (it's normal)\n",
|
|
|
|
rdbi->bsn,
|
|
|
|
m_window.v_q(), m_window.mod_sns(m_window.v_q() + ws - 1));
|
2021-05-11 12:40:41 +00:00
|
|
|
continue;
|
2015-12-14 12:36:13 +00:00
|
|
|
} else if (m_window.is_received(rdbi->bsn)) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"BSN %d already received\n", rdbi->bsn);
|
2015-12-14 12:36:13 +00:00
|
|
|
continue;
|
2021-05-11 12:40:41 +00:00
|
|
|
}
|
2015-12-14 12:36:13 +00:00
|
|
|
|
|
|
|
/* Store block and meta info to BSN buffer */
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "BSN %d storing in window (%d..%d)\n",
|
|
|
|
rdbi->bsn, m_window.v_q(),
|
|
|
|
m_window.mod_sns(m_window.v_q() + ws - 1));
|
2015-12-14 12:36:13 +00:00
|
|
|
block = m_rlc.block(rdbi->bsn);
|
2016-06-14 13:29:18 +00:00
|
|
|
OSMO_ASSERT(rdbi->data_len <= sizeof(block->block));
|
2015-12-14 12:36:13 +00:00
|
|
|
rlc_data = &(block->block[0]);
|
2016-07-26 12:56:21 +00:00
|
|
|
|
2015-12-14 12:36:13 +00:00
|
|
|
if (rdbi->spb) {
|
2016-07-26 12:56:21 +00:00
|
|
|
egprs_rlc_ul_reseg_bsn_state assemble_status;
|
|
|
|
|
|
|
|
assemble_status = handle_egprs_ul_spb(rlc,
|
|
|
|
block, data, block_idx);
|
2015-12-14 12:36:13 +00:00
|
|
|
|
2016-07-26 12:56:21 +00:00
|
|
|
if (assemble_status != EGPRS_RESEG_DEFAULT)
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
block->block_info = *rdbi;
|
|
|
|
block->cs_last = rlc->cs;
|
|
|
|
block->len =
|
|
|
|
Decoding::rlc_copy_to_aligned_buffer(rlc,
|
|
|
|
block_idx, data, rlc_data);
|
|
|
|
}
|
2015-12-14 12:36:13 +00:00
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"data_length=%d, data=%s\n",
|
|
|
|
block->len, osmo_hexdump(rlc_data, block->len));
|
2015-12-14 12:36:13 +00:00
|
|
|
/* Get/Handle TLLI */
|
|
|
|
if (rdbi->ti) {
|
|
|
|
num_chunks = Decoding::rlc_data_from_ul_data(
|
|
|
|
rdbi, rlc->cs, rlc_data, NULL, 0, &new_tlli);
|
|
|
|
|
|
|
|
if (num_chunks < 0) {
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_DECODE_ERRORS);
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_NOTICE,
|
|
|
|
"Failed to decode TLLI of %s UL DATA TFI=%d.\n",
|
2019-03-05 13:59:03 +00:00
|
|
|
mcs_name(rlc->cs), rlc->tfi);
|
2015-12-14 12:36:13 +00:00
|
|
|
m_window.invalidate_bsn(rdbi->bsn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!this->is_tlli_valid()) {
|
TLLI 0x00000000 is a valid TLLI, use 0xffffffff instead
The assumption that TLLI 0x00000000 is invalid and can be used
as the initializer is wrong. Similar to TMSI, 0x00000000 is a
perfectly valid value, while 0xffffffff is reserved - use it.
According to 3GPP TS 23.003, section 2.4, a TMSI/P-TMSI with
all 32 bits equal to 1 is special and shall not be allocated by
the network. The reason is that it must be stored on the SIM,
where 'ff'O represents the erased state. According to section
2.6 of the same document, a local/foreign TLLI is derived from
P-TMSI, so the same rule applies to TLLI.
I manually checked and corrected all occurances of 'tlli' in the
code. The test expectations have been adjusted with this command:
$ find tests/ -name "*.err" | xargs sed -i "s/0x00000000/0xffffffff/g"
so there should be no behavior change. The only exception is
the 'TypesTest', where TLLI 0xffffffff is being encoded and
expected in the hexdump, so I regenerated the test output.
Change-Id: Ie89fab75ecc1d8b5e238d3ff214ea7ac830b68b5
Related: OS#4844
2020-11-08 06:27:35 +00:00
|
|
|
if (new_tlli == GSM_RESERVED_TMSI) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_NOTICE,
|
TLLI 0x00000000 is a valid TLLI, use 0xffffffff instead
The assumption that TLLI 0x00000000 is invalid and can be used
as the initializer is wrong. Similar to TMSI, 0x00000000 is a
perfectly valid value, while 0xffffffff is reserved - use it.
According to 3GPP TS 23.003, section 2.4, a TMSI/P-TMSI with
all 32 bits equal to 1 is special and shall not be allocated by
the network. The reason is that it must be stored on the SIM,
where 'ff'O represents the erased state. According to section
2.6 of the same document, a local/foreign TLLI is derived from
P-TMSI, so the same rule applies to TLLI.
I manually checked and corrected all occurances of 'tlli' in the
code. The test expectations have been adjusted with this command:
$ find tests/ -name "*.err" | xargs sed -i "s/0x00000000/0xffffffff/g"
so there should be no behavior change. The only exception is
the 'TypesTest', where TLLI 0xffffffff is being encoded and
expected in the hexdump, so I regenerated the test output.
Change-Id: Ie89fab75ecc1d8b5e238d3ff214ea7ac830b68b5
Related: OS#4844
2020-11-08 06:27:35 +00:00
|
|
|
"TLLI is 0x%08x within UL DATA?!?\n",
|
|
|
|
new_tlli);
|
2015-12-14 12:36:13 +00:00
|
|
|
m_window.invalidate_bsn(rdbi->bsn);
|
|
|
|
continue;
|
|
|
|
}
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_INFO,
|
|
|
|
"Decoded premier TLLI=0x%08x of UL DATA TFI=%d.\n",
|
2020-04-20 04:26:12 +00:00
|
|
|
new_tlli, rlc->tfi);
|
2020-06-26 12:20:37 +00:00
|
|
|
update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
|
TLLI 0x00000000 is a valid TLLI, use 0xffffffff instead
The assumption that TLLI 0x00000000 is invalid and can be used
as the initializer is wrong. Similar to TMSI, 0x00000000 is a
perfectly valid value, while 0xffffffff is reserved - use it.
According to 3GPP TS 23.003, section 2.4, a TMSI/P-TMSI with
all 32 bits equal to 1 is special and shall not be allocated by
the network. The reason is that it must be stored on the SIM,
where 'ff'O represents the erased state. According to section
2.6 of the same document, a local/foreign TLLI is derived from
P-TMSI, so the same rule applies to TLLI.
I manually checked and corrected all occurances of 'tlli' in the
code. The test expectations have been adjusted with this command:
$ find tests/ -name "*.err" | xargs sed -i "s/0x00000000/0xffffffff/g"
so there should be no behavior change. The only exception is
the 'TypesTest', where TLLI 0xffffffff is being encoded and
expected in the hexdump, so I regenerated the test output.
Change-Id: Ie89fab75ecc1d8b5e238d3ff214ea7ac830b68b5
Related: OS#4844
2020-11-08 06:27:35 +00:00
|
|
|
} else if (new_tlli != GSM_RESERVED_TMSI && new_tlli != tlli()) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_NOTICE,
|
2020-11-06 19:03:24 +00:00
|
|
|
"Decoded TLLI=%08x mismatch on UL DATA TFI=%d. (Ignoring due to contention resolution)\n",
|
|
|
|
new_tlli, rlc->tfi);
|
2015-12-14 12:36:13 +00:00
|
|
|
m_window.invalidate_bsn(rdbi->bsn);
|
|
|
|
continue;
|
|
|
|
}
|
2021-05-11 12:40:41 +00:00
|
|
|
} else if (!is_tlli_valid()) {
|
|
|
|
LOGPTBFUL(this, LOGL_NOTICE, "Missing TLLI within UL DATA.\n");
|
|
|
|
m_window.invalidate_bsn(rdbi->bsn);
|
|
|
|
continue;
|
2015-12-14 12:36:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_window.receive_bsn(rdbi->bsn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Raise V(Q) if possible, and retrieve LLC frames from blocks.
|
|
|
|
* This is looped until there is a gap (non received block) or
|
|
|
|
* the window is empty.*/
|
|
|
|
const uint16_t v_q_beg = m_window.v_q();
|
|
|
|
const uint16_t count = m_window.raise_v_q();
|
|
|
|
|
|
|
|
/* Retrieve LLC frames from blocks that are ready */
|
|
|
|
for (uint16_t i = 0; i < count; ++i) {
|
2015-12-23 15:29:07 +00:00
|
|
|
uint16_t index = m_window.mod_sns(v_q_beg + i);
|
2015-12-14 12:36:13 +00:00
|
|
|
assemble_forward_llc(m_rlc.block(index));
|
|
|
|
}
|
|
|
|
|
2020-05-15 14:57:48 +00:00
|
|
|
/* Last frame in buffer: */
|
|
|
|
block = m_rlc.block(m_window.mod_sns(m_window.v_r() - 1));
|
|
|
|
rdbi = &block->block_info;
|
|
|
|
|
|
|
|
/* Check if we already received all data TBF had to send: */
|
2021-05-14 10:50:46 +00:00
|
|
|
if (this->state_is(TBF_ST_FLOW) /* still in flow state */
|
2021-05-11 12:54:40 +00:00
|
|
|
&& this->m_window.v_q() == this->m_window.v_r() /* if complete */
|
|
|
|
&& block->len) { /* if there was ever a last block received */
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"No gaps in received block, last block: BSN=%d CV=%d\n",
|
|
|
|
rdbi->bsn, rdbi->cv);
|
2015-12-14 12:36:13 +00:00
|
|
|
if (rdbi->cv == 0) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "Finished with UL TBF\n");
|
2021-05-14 10:50:46 +00:00
|
|
|
TBF_SET_STATE(this, TBF_ST_FINISHED);
|
2015-12-14 12:36:13 +00:00
|
|
|
/* Reset N3103 counter. */
|
2018-02-20 17:16:11 +00:00
|
|
|
this->n_reset(N3103);
|
2015-12-14 12:36:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If TLLI is included or if we received half of the window, we send
|
|
|
|
* an ack/nack */
|
2021-05-11 12:54:40 +00:00
|
|
|
maybe_schedule_uplink_acknack(rlc, block->len && rdbi->cv == 0);
|
2015-12-14 12:36:13 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_ul_tbf::maybe_schedule_uplink_acknack(
|
2020-05-15 14:57:48 +00:00
|
|
|
const gprs_rlc_data_info *rlc, bool countdown_finished)
|
2015-12-14 12:36:13 +00:00
|
|
|
{
|
2020-05-15 14:40:18 +00:00
|
|
|
bool require_ack = false;
|
2015-12-14 12:36:13 +00:00
|
|
|
bool have_ti = rlc->block_info[0].ti ||
|
|
|
|
(rlc->num_data_blocks > 1 && rlc->block_info[1].ti);
|
|
|
|
|
2020-05-15 14:40:18 +00:00
|
|
|
if (rlc->si) {
|
|
|
|
require_ack = true;
|
|
|
|
LOGPTBFUL(this, LOGL_NOTICE,
|
|
|
|
"Scheduling Ack/Nack, because MS is stalled.\n");
|
|
|
|
}
|
|
|
|
if (have_ti) {
|
|
|
|
require_ack = true;
|
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Scheduling Ack/Nack, because TLLI is included.\n");
|
|
|
|
}
|
2020-05-15 14:57:48 +00:00
|
|
|
if (countdown_finished) {
|
2020-05-15 14:40:18 +00:00
|
|
|
require_ack = true;
|
2021-05-14 10:50:46 +00:00
|
|
|
if (state_is(TBF_ST_FLOW))
|
2020-05-15 14:57:48 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Scheduling Ack/Nack, because some data is missing and last block has CV==0.\n");
|
2021-05-14 10:50:46 +00:00
|
|
|
else if (state_is(TBF_ST_FINISHED))
|
2020-05-15 14:57:48 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Scheduling final Ack/Nack, because all data was received and last block has CV==0.\n");
|
2020-05-15 14:40:18 +00:00
|
|
|
}
|
|
|
|
if ((m_rx_counter % SEND_ACK_AFTER_FRAMES) == 0) {
|
|
|
|
require_ack = true;
|
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Scheduling Ack/Nack, because %d frames received.\n",
|
|
|
|
SEND_ACK_AFTER_FRAMES);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!require_ack)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ul_ack_state_is(GPRS_RLCMAC_UL_ACK_NONE)) {
|
|
|
|
/* trigger sending at next RTS */
|
|
|
|
TBF_SET_ACK_STATE(this, GPRS_RLCMAC_UL_ACK_SEND_ACK);
|
|
|
|
} else {
|
|
|
|
/* already triggered */
|
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Sending Ack/Nack already scheduled, no need to re-schedule\n");
|
2014-08-08 10:14:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send Uplink unit-data to SGSN. */
|
|
|
|
int gprs_rlcmac_ul_tbf::snd_ul_ud()
|
|
|
|
{
|
|
|
|
uint8_t qos_profile[3];
|
|
|
|
struct msgb *llc_pdu;
|
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
|
|
|
unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + llc_frame_length(&m_llc);
|
2021-01-21 17:02:40 +00:00
|
|
|
struct bssgp_bvc_ctx *bctx = bts->pcu->bssgp.bctx;
|
2014-08-08 10:14:12 +00:00
|
|
|
|
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
|
|
|
LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] %s len=%d\n", tbf_name(this), llc_frame_length(&m_llc));
|
2014-08-08 10:14:12 +00:00
|
|
|
if (!bctx) {
|
|
|
|
LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
|
|
|
|
m_llc.reset_frame_space();
|
|
|
|
return -EIO;
|
|
|
|
}
|
2019-09-25 15:48:35 +00:00
|
|
|
|
2014-08-08 10:14:12 +00:00
|
|
|
llc_pdu = msgb_alloc_headroom(msg_len, msg_len,"llc_pdu");
|
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
|
|
|
uint8_t *buf = msgb_push(llc_pdu, TL16V_GROSS_LEN(sizeof(uint8_t)*llc_frame_length(&m_llc)));
|
|
|
|
tl16v_put(buf, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*llc_frame_length(&m_llc), m_llc.frame);
|
2014-08-08 10:14:12 +00:00
|
|
|
qos_profile[0] = QOS_PROFILE >> 16;
|
|
|
|
qos_profile[1] = QOS_PROFILE >> 8;
|
|
|
|
qos_profile[2] = QOS_PROFILE;
|
|
|
|
bssgp_tx_ul_ud(bctx, tlli(), qos_profile, llc_pdu);
|
|
|
|
|
|
|
|
m_llc.reset_frame_space();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-26 12:56:21 +00:00
|
|
|
egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_second_seg(
|
|
|
|
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
|
|
|
uint8_t *data, const uint8_t block_idx)
|
|
|
|
{
|
|
|
|
const gprs_rlc_data_block_info *rdbi = &rlc->block_info[block_idx];
|
|
|
|
union split_block_status *spb_status = &block->spb_status;
|
|
|
|
uint8_t *rlc_data = &block->block[0];
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_SPB_UL_SECOND_SEGMENT);
|
2016-12-16 07:27:18 +00:00
|
|
|
|
2016-07-26 12:56:21 +00:00
|
|
|
if (spb_status->block_status_ul &
|
|
|
|
EGPRS_RESEG_FIRST_SEG_RXD) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Second seg is received first seg is already present set the status to complete\n");
|
2016-07-26 12:56:21 +00:00
|
|
|
spb_status->block_status_ul = EGPRS_RESEG_DEFAULT;
|
|
|
|
|
|
|
|
block->len += Decoding::rlc_copy_to_aligned_buffer(rlc,
|
|
|
|
block_idx, data, rlc_data + block->len);
|
|
|
|
block->block_info.data_len += rdbi->data_len;
|
|
|
|
} else if (spb_status->block_status_ul == EGPRS_RESEG_DEFAULT) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Second seg is received first seg is not received set the status to second seg received\n");
|
2016-07-26 12:56:21 +00:00
|
|
|
|
|
|
|
block->len = Decoding::rlc_copy_to_aligned_buffer(rlc,
|
|
|
|
block_idx, data,
|
|
|
|
rlc_data + rlc->block_info[block_idx].data_len);
|
|
|
|
|
|
|
|
spb_status->block_status_ul = EGPRS_RESEG_SECOND_SEG_RXD;
|
|
|
|
block->block_info = *rdbi;
|
|
|
|
}
|
|
|
|
return spb_status->block_status_ul;
|
|
|
|
}
|
|
|
|
|
|
|
|
egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_first_seg(
|
|
|
|
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
|
|
|
uint8_t *data, const uint8_t block_idx)
|
|
|
|
{
|
|
|
|
const gprs_rlc_data_block_info *rdbi = &rlc->block_info[block_idx];
|
|
|
|
uint8_t *rlc_data = &block->block[0];
|
|
|
|
union split_block_status *spb_status = &block->spb_status;
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_SPB_UL_FIRST_SEGMENT);
|
2016-12-16 07:27:18 +00:00
|
|
|
|
2016-07-26 12:56:21 +00:00
|
|
|
if (spb_status->block_status_ul & EGPRS_RESEG_SECOND_SEG_RXD) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"First seg is received second seg is already present set the status to complete\n");
|
2016-07-26 12:56:21 +00:00
|
|
|
|
|
|
|
block->len += Decoding::rlc_copy_to_aligned_buffer(rlc,
|
|
|
|
block_idx, data, rlc_data);
|
|
|
|
|
|
|
|
block->block_info.data_len = block->len;
|
|
|
|
spb_status->block_status_ul = EGPRS_RESEG_DEFAULT;
|
|
|
|
} else if (spb_status->block_status_ul == EGPRS_RESEG_DEFAULT) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"First seg is received second seg is not received set the status to first seg received\n");
|
2016-07-26 12:56:21 +00:00
|
|
|
|
|
|
|
spb_status->block_status_ul = EGPRS_RESEG_FIRST_SEG_RXD;
|
|
|
|
block->len = Decoding::rlc_copy_to_aligned_buffer(rlc,
|
|
|
|
block_idx, data, rlc_data);
|
|
|
|
block->block_info = *rdbi;
|
|
|
|
}
|
|
|
|
return spb_status->block_status_ul;
|
|
|
|
}
|
|
|
|
|
|
|
|
egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_spb(
|
|
|
|
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
|
|
|
uint8_t *data, const uint8_t block_idx)
|
|
|
|
{
|
|
|
|
const gprs_rlc_data_block_info *rdbi = &rlc->block_info[block_idx];
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Got SPB(%d) cs(%s) data block with BSN (%d), TFI(%d).\n",
|
2019-03-05 13:59:03 +00:00
|
|
|
rdbi->spb, mcs_name(rlc->cs), rdbi->bsn, rlc->tfi);
|
2016-07-26 12:56:21 +00:00
|
|
|
|
|
|
|
egprs_rlc_ul_reseg_bsn_state assemble_status = EGPRS_RESEG_INVALID;
|
|
|
|
|
|
|
|
/* Section 10.4.8b of 44.060*/
|
|
|
|
if (rdbi->spb == 2)
|
|
|
|
assemble_status = handle_egprs_ul_first_seg(rlc,
|
|
|
|
block, data, block_idx);
|
|
|
|
else if (rdbi->spb == 3)
|
|
|
|
assemble_status = handle_egprs_ul_second_seg(rlc,
|
|
|
|
block, data, block_idx);
|
|
|
|
else {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_ERROR,
|
|
|
|
"spb(%d) Not supported SPB for this EGPRS configuration\n",
|
|
|
|
rdbi->spb);
|
2016-07-26 12:56:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When the block is successfully constructed out of segmented blocks
|
|
|
|
* upgrade the MCS to the type 2
|
|
|
|
*/
|
|
|
|
if (assemble_status == EGPRS_RESEG_DEFAULT) {
|
2020-05-18 09:35:35 +00:00
|
|
|
switch (rlc->cs) {
|
2019-03-06 16:04:59 +00:00
|
|
|
case MCS3 :
|
|
|
|
block->cs_last = MCS6;
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "Upgrading to MCS6\n");
|
2016-07-26 12:56:21 +00:00
|
|
|
break;
|
2019-03-06 16:04:59 +00:00
|
|
|
case MCS2 :
|
|
|
|
block->cs_last = MCS5;
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "Upgrading to MCS5\n");
|
2016-07-26 12:56:21 +00:00
|
|
|
break;
|
2019-03-06 16:04:59 +00:00
|
|
|
case MCS1 :
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "Upgrading to MCS4\n");
|
2019-03-06 16:04:59 +00:00
|
|
|
block->cs_last = MCS4;
|
2016-07-26 12:56:21 +00:00
|
|
|
break;
|
|
|
|
default:
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_ERROR,
|
|
|
|
"cs(%s) Error in Upgrading to higher MCS\n",
|
2019-03-05 13:59:03 +00:00
|
|
|
mcs_name(rlc->cs));
|
2016-07-26 12:56:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return assemble_status;
|
|
|
|
}
|
2016-11-10 12:46:30 +00:00
|
|
|
|
2019-03-13 17:40:19 +00:00
|
|
|
void gprs_rlcmac_ul_tbf::update_coding_scheme_counter_ul(enum CodingScheme cs)
|
2016-11-10 12:46:30 +00:00
|
|
|
{
|
2019-03-13 17:40:19 +00:00
|
|
|
switch (cs) {
|
|
|
|
case CS1:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_GPRS_UL_CS1);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_gprs_ctrs, TBF_CTR_GPRS_UL_CS1));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case CS2:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_GPRS_UL_CS2);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_gprs_ctrs, TBF_CTR_GPRS_UL_CS2));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case CS3:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_GPRS_UL_CS3);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_gprs_ctrs, TBF_CTR_GPRS_UL_CS3));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case CS4:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_GPRS_UL_CS4);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_gprs_ctrs, TBF_CTR_GPRS_UL_CS4));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS1:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS1);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS1));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS2:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS2);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS2));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS3:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS3);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS3));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS4:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS4);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS4));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS5:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS5);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS5));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS6:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS6);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS6));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS7:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS7);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS7));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS8:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS8);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS8));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
case MCS9:
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_EGPRS_UL_MCS9);
|
2021-06-04 15:05:51 +00:00
|
|
|
rate_ctr_inc(rate_ctr_group_get_ctr(m_ul_egprs_ctrs, TBF_CTR_EGPRS_UL_MCS9));
|
2019-03-13 17:40:19 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGPTBFUL(this, LOGL_ERROR, "attempting to update rate counters for unsupported (M)CS %s\n",
|
|
|
|
mcs_name(cs));
|
2016-11-10 12:46:30 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-16 10:11:21 +00:00
|
|
|
|
2017-12-14 14:02:33 +00:00
|
|
|
void gprs_rlcmac_ul_tbf::set_window_size()
|
2017-01-16 10:11:21 +00:00
|
|
|
{
|
2021-01-14 15:48:38 +00:00
|
|
|
const struct gprs_rlcmac_bts *b = bts;
|
2018-12-11 15:47:30 +00:00
|
|
|
uint16_t ws = egprs_window_size(b, ul_slots());
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_INFO, "setting EGPRS UL window size to %u, base(%u) slots(%u) ws_pdch(%u)\n",
|
2021-01-14 13:30:03 +00:00
|
|
|
ws, bts->pcu->vty.ws_base, pcu_bitcount(ul_slots()), bts->pcu->vty.ws_pdch);
|
2017-01-16 10:11:21 +00:00
|
|
|
m_window.set_ws(ws);
|
|
|
|
}
|
2020-10-23 19:11:41 +00:00
|
|
|
|
2020-10-23 19:00:23 +00:00
|
|
|
gprs_rlc_window *gprs_rlcmac_ul_tbf::window()
|
2020-10-23 19:11:41 +00:00
|
|
|
{
|
|
|
|
return &m_window;
|
|
|
|
}
|
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
|
|
|
|
2021-03-24 13:45:43 +00:00
|
|
|
void gprs_rlcmac_ul_tbf::usf_timeout()
|
|
|
|
{
|
|
|
|
if (n_inc(N3101)) {
|
2021-05-14 10:50:46 +00:00
|
|
|
TBF_SET_STATE(this, TBF_ST_RELEASING);
|
2021-03-24 13:45:43 +00:00
|
|
|
T_START(this, T3169, 3169, "MAX N3101 reached", false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 gprs_rlcmac_ul_tbf *as_ul_tbf(struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
if (tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
|
|
|
|
return static_cast<gprs_rlcmac_ul_tbf *>(tbf);
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-03-24 13:45:43 +00:00
|
|
|
|
|
|
|
void tbf_usf_timeout(struct gprs_rlcmac_ul_tbf *tbf)
|
|
|
|
{
|
|
|
|
tbf->usf_timeout();
|
|
|
|
}
|