2013-08-24 16:31:27 +00:00
|
|
|
/* Copied from gprs_bssgp_pcu.cpp
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Ivan Klyuchnikov
|
2013-08-24 19:26:42 +00:00
|
|
|
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
|
2013-08-24 16:31:27 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2020-03-26 14:56:15 +00:00
|
|
|
#include <new>
|
2020-09-22 11:41:00 +00:00
|
|
|
#include <sstream>
|
2020-03-26 14:56:15 +00:00
|
|
|
|
2013-10-17 15:01:54 +00:00
|
|
|
#include <bts.h>
|
2013-08-24 16:31:27 +00:00
|
|
|
#include <tbf.h>
|
2019-09-25 15:47:02 +00:00
|
|
|
#include <tbf_dl.h>
|
|
|
|
#include <tbf_ul.h>
|
2013-10-26 15:32:04 +00:00
|
|
|
#include <rlc.h>
|
2013-10-26 18:45:35 +00:00
|
|
|
#include <encoding.h>
|
2013-08-24 16:31:27 +00:00
|
|
|
#include <gprs_rlcmac.h>
|
|
|
|
#include <gprs_debug.h>
|
2015-05-08 10:13:08 +00:00
|
|
|
#include <gprs_ms.h>
|
2016-01-19 14:53:30 +00:00
|
|
|
#include <pcu_utils.h>
|
2018-01-26 12:31:42 +00:00
|
|
|
#include <gprs_ms_storage.h>
|
|
|
|
#include <sba.h>
|
2018-02-19 16:17:28 +00:00
|
|
|
#include <pdch.h>
|
2013-08-24 16:31:27 +00:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include <osmocom/core/msgb.h>
|
2017-12-20 16:31:13 +00:00
|
|
|
#include <osmocom/core/utils.h>
|
2013-10-16 15:55:57 +00:00
|
|
|
#include <osmocom/core/talloc.h>
|
2016-12-08 11:45:17 +00:00
|
|
|
#include <osmocom/core/stats.h>
|
2017-12-20 17:13:29 +00:00
|
|
|
#include <osmocom/core/logging.h>
|
2018-05-25 13:12:30 +00:00
|
|
|
#include <osmocom/core/timer_compat.h>
|
2020-03-26 14:06:11 +00:00
|
|
|
#include <osmocom/core/bitvec.h>
|
|
|
|
#include <osmocom/core/rate_ctr.h>
|
|
|
|
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
2020-03-26 14:14:01 +00:00
|
|
|
|
|
|
|
#include "gsm_rlcmac.h"
|
2020-05-18 09:35:35 +00:00
|
|
|
#include "coding_scheme.h"
|
2021-02-01 13:52:48 +00:00
|
|
|
#include "nacc_fsm.h"
|
2013-08-24 16:31:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2013-10-16 16:09:19 +00:00
|
|
|
extern void *tall_pcu_ctx;
|
|
|
|
|
2020-10-23 20:30:04 +00:00
|
|
|
unsigned int next_tbf_ctr_group_id = 0; /* Incrementing group id */
|
2018-07-10 13:44:47 +00:00
|
|
|
|
2013-10-26 15:56:15 +00:00
|
|
|
static void tbf_timer_cb(void *_tbf);
|
|
|
|
|
2018-01-24 10:00:17 +00:00
|
|
|
const struct value_string gprs_rlcmac_tbf_poll_state_names[] = {
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_POLL_NONE),
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_POLL_SCHED), /* a polling was scheduled */
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2017-01-05 17:26:58 +00:00
|
|
|
const struct value_string gprs_rlcmac_tbf_dl_ass_state_names[] = {
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_DL_ASS_NONE),
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_DL_ASS_SEND_ASS),
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_DL_ASS_WAIT_ACK),
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct value_string gprs_rlcmac_tbf_ul_ass_state_names[] = {
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ASS_NONE),
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ASS_SEND_ASS),
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ),
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ASS_WAIT_ACK),
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2018-01-23 19:16:23 +00:00
|
|
|
const struct value_string gprs_rlcmac_tbf_ul_ack_state_names[] = {
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ACK_NONE),
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ACK_SEND_ACK), /* send acknowledge on next RTS */
|
|
|
|
OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ACK_WAIT_ACK), /* wait for PACKET CONTROL ACK */
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2018-02-20 17:16:11 +00:00
|
|
|
static const struct value_string tbf_counters_names[] = {
|
|
|
|
OSMO_VALUE_STRING(N3101),
|
|
|
|
OSMO_VALUE_STRING(N3103),
|
|
|
|
OSMO_VALUE_STRING(N3105),
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2017-12-20 16:31:13 +00:00
|
|
|
static const struct value_string tbf_timers_names[] = {
|
2017-12-20 17:05:29 +00:00
|
|
|
OSMO_VALUE_STRING(T0),
|
2017-12-20 16:31:13 +00:00
|
|
|
OSMO_VALUE_STRING(T3169),
|
|
|
|
OSMO_VALUE_STRING(T3191),
|
|
|
|
OSMO_VALUE_STRING(T3193),
|
|
|
|
OSMO_VALUE_STRING(T3195),
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2016-12-08 11:45:17 +00:00
|
|
|
static const struct rate_ctr_desc tbf_ctr_description[] = {
|
2018-07-10 13:16:49 +00:00
|
|
|
{ "rlc:nacked", "RLC Nacked " },
|
2016-12-08 11:45:17 +00:00
|
|
|
};
|
|
|
|
|
2020-10-23 20:30:04 +00:00
|
|
|
const struct rate_ctr_group_desc tbf_ctrg_desc = {
|
2018-07-10 13:16:49 +00:00
|
|
|
"pcu:tbf",
|
2016-12-08 11:45:17 +00:00
|
|
|
"TBF Statistics",
|
|
|
|
OSMO_STATS_CLASS_SUBSCRIBER,
|
|
|
|
ARRAY_SIZE(tbf_ctr_description),
|
|
|
|
tbf_ctr_description,
|
|
|
|
};
|
|
|
|
|
2015-08-28 10:07:14 +00:00
|
|
|
gprs_rlcmac_tbf::Meas::Meas() :
|
|
|
|
rssi_sum(0),
|
|
|
|
rssi_num(0)
|
|
|
|
{
|
2018-05-25 13:12:30 +00:00
|
|
|
timespecclear(&rssi_tv);
|
2015-08-28 10:07:14 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_rlcmac_tbf_direction dir) :
|
2015-08-28 10:07:14 +00:00
|
|
|
state_flags(0),
|
2015-08-21 13:24:02 +00:00
|
|
|
direction(dir),
|
2015-08-28 10:07:14 +00:00
|
|
|
trx(NULL),
|
|
|
|
first_ts(0),
|
|
|
|
first_common_ts(0),
|
|
|
|
control_ts(0xff),
|
|
|
|
poll_fn(0),
|
2016-01-22 16:58:17 +00:00
|
|
|
poll_ts(0),
|
2015-08-28 10:07:14 +00:00
|
|
|
fT(0),
|
|
|
|
num_fT_exp(0),
|
|
|
|
was_releasing(0),
|
|
|
|
upgrade_to_multislot(0),
|
|
|
|
bts(bts_),
|
|
|
|
m_tfi(0),
|
|
|
|
m_created_ts(0),
|
2017-02-08 16:07:40 +00:00
|
|
|
m_ctrs(NULL),
|
2017-12-06 12:35:08 +00:00
|
|
|
state(GPRS_RLCMAC_NULL),
|
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
|
|
|
m_ms(ms),
|
2018-01-23 19:09:06 +00:00
|
|
|
dl_ass_state(GPRS_RLCMAC_DL_ASS_NONE),
|
|
|
|
ul_ass_state(GPRS_RLCMAC_UL_ASS_NONE),
|
2018-01-23 19:16:23 +00:00
|
|
|
ul_ack_state(GPRS_RLCMAC_UL_ACK_NONE),
|
2018-01-24 10:00:17 +00:00
|
|
|
poll_state(GPRS_RLCMAC_POLL_NONE),
|
2017-02-08 16:07:40 +00:00
|
|
|
m_egprs_enabled(false)
|
2015-08-20 15:49:03 +00:00
|
|
|
{
|
2015-08-28 10:07:14 +00:00
|
|
|
/* The classes of these members do not have proper constructors yet.
|
|
|
|
* Just set them to 0 like talloc_zero did */
|
|
|
|
memset(&pdch, 0, sizeof(pdch));
|
2019-09-05 12:40:24 +00:00
|
|
|
memset(&Tarr, 0, sizeof(Tarr));
|
|
|
|
memset(&Narr, 0, sizeof(Narr));
|
2015-08-28 10:07:14 +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
|
|
|
memset(&m_ms_list, 0, sizeof(m_ms_list));
|
|
|
|
m_ms_list.entry = this;
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
memset(&m_bts_list, 0, sizeof(m_bts_list));
|
|
|
|
m_bts_list.entry = this;
|
|
|
|
|
2018-05-16 13:20:39 +00:00
|
|
|
m_rlc.init();
|
2015-08-28 10:07:14 +00:00
|
|
|
m_llc.init();
|
|
|
|
|
|
|
|
m_name_buf[0] = '\0';
|
2015-08-20 15:49:03 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 09:56:50 +00:00
|
|
|
uint32_t gprs_rlcmac_tbf::tlli() const
|
|
|
|
{
|
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 m_ms ? ms_tlli(m_ms) : GSM_RESERVED_TMSI;
|
2015-05-18 09:56:50 +00:00
|
|
|
}
|
|
|
|
|
2015-05-21 09:07:16 +00:00
|
|
|
const char *gprs_rlcmac_tbf::imsi() const
|
2013-08-24 18:51:06 +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
|
|
|
return ms_imsi(m_ms);
|
2013-08-24 18:51:06 +00:00
|
|
|
}
|
|
|
|
|
2015-05-22 15:48:04 +00:00
|
|
|
uint8_t gprs_rlcmac_tbf::ta() const
|
|
|
|
{
|
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 ms_ta(m_ms);
|
2015-05-22 15:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_tbf::set_ta(uint8_t ta)
|
|
|
|
{
|
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(m_ms, ta);
|
2015-05-22 15:48:04 +00:00
|
|
|
}
|
|
|
|
|
2015-06-02 10:33:30 +00:00
|
|
|
uint8_t gprs_rlcmac_tbf::ms_class() const
|
|
|
|
{
|
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 ms_ms_class(m_ms);
|
2015-06-02 10:33:30 +00:00
|
|
|
}
|
|
|
|
|
2020-05-18 09:35:35 +00:00
|
|
|
enum CodingScheme gprs_rlcmac_tbf::current_cs() const
|
2015-06-02 14:00:41 +00:00
|
|
|
{
|
2020-05-18 09:35:35 +00:00
|
|
|
enum CodingScheme cs;
|
2021-01-25 11:05:32 +00:00
|
|
|
enum mcs_kind req_mcs_kind = is_egprs_enabled() ? EGPRS : GPRS;
|
2020-05-18 09:35:35 +00:00
|
|
|
|
2015-06-02 14:00:41 +00:00
|
|
|
if (direction == GPRS_RLCMAC_UL_TBF)
|
2021-01-25 10:37:19 +00:00
|
|
|
cs = ms_current_cs_ul(m_ms);
|
2015-06-02 14:00:41 +00:00
|
|
|
else
|
2021-01-25 11:05:32 +00:00
|
|
|
cs = ms_current_cs_dl(m_ms, req_mcs_kind);
|
2015-06-02 14:00:41 +00:00
|
|
|
|
2016-01-05 14:33:03 +00:00
|
|
|
return cs;
|
2015-06-02 14:00:41 +00:00
|
|
|
}
|
|
|
|
|
2015-05-28 17:07:01 +00:00
|
|
|
gprs_llc_queue *gprs_rlcmac_tbf::llc_queue()
|
|
|
|
{
|
2021-01-25 10:37:19 +00:00
|
|
|
return ms_llc_queue(m_ms);
|
2015-05-28 17:07:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const gprs_llc_queue *gprs_rlcmac_tbf::llc_queue() const
|
|
|
|
{
|
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 ms_llc_queue(m_ms);
|
2016-08-21 17:38:30 +00:00
|
|
|
}
|
|
|
|
|
2015-05-08 10:13:08 +00:00
|
|
|
void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
|
|
|
|
{
|
|
|
|
if (m_ms == ms)
|
|
|
|
return;
|
|
|
|
|
2015-05-22 15:48:04 +00:00
|
|
|
if (m_ms) {
|
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_detach_tbf(m_ms, this);
|
2015-05-22 15:48:04 +00:00
|
|
|
}
|
2015-05-08 10:13:08 +00:00
|
|
|
|
|
|
|
m_ms = ms;
|
|
|
|
|
|
|
|
if (m_ms)
|
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_attach_tbf(m_ms, this);
|
2015-05-08 10:13:08 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 12:35:11 +00:00
|
|
|
void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
|
2015-05-08 10:13:08 +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
|
|
|
if (tlli == GSM_RESERVED_TMSI)
|
2015-05-21 14:58:22 +00:00
|
|
|
return;
|
|
|
|
|
2015-08-16 16:19:32 +00:00
|
|
|
/* TODO: When the TLLI does not match the ms, check if there is another
|
|
|
|
* MS object that belongs to that TLLI and if yes make sure one of them
|
|
|
|
* gets deleted. This is the same problem that can arise with
|
2020-10-26 11:40:11 +00:00
|
|
|
* IMSI in gprs_rlcmac_dl_tbf::handle() so there should be a unified solution */
|
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_check_tlli(ms(), tlli)) {
|
2015-08-16 16:19:32 +00:00
|
|
|
GprsMs *old_ms;
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
old_ms = bts_ms_store(bts)->get_ms(tlli, 0, NULL);
|
2015-08-16 16:19:32 +00:00
|
|
|
if (old_ms)
|
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_merge_and_clear_ms(ms(), old_ms);
|
2015-08-16 16:19:32 +00:00
|
|
|
}
|
|
|
|
|
2015-05-21 14:58:22 +00:00
|
|
|
if (dir == GPRS_RLCMAC_UL_TBF)
|
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);
|
2015-05-15 13:50:43 +00:00
|
|
|
else
|
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_confirm_tlli(ms(), tlli);
|
2014-08-15 14:52:09 +00:00
|
|
|
}
|
|
|
|
|
2013-10-16 15:55:57 +00:00
|
|
|
static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
int ts;
|
|
|
|
|
2015-06-29 11:45:05 +00:00
|
|
|
for (ts = 0; ts < 8; ts++) {
|
|
|
|
if (!tbf->pdch[ts])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tbf->pdch[ts]->detach_tbf(tbf);
|
|
|
|
tbf->pdch[ts] = NULL;
|
2013-10-16 15:55:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tbf_free(struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
2016-01-21 19:12:04 +00:00
|
|
|
/* update counters */
|
|
|
|
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
|
2016-12-16 07:27:18 +00:00
|
|
|
gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf);
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_UL_FREED);
|
2016-01-21 19:12:04 +00:00
|
|
|
if (tbf->state_is(GPRS_RLCMAC_FLOW))
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_UL_ABORTED);
|
2016-12-16 07:27:18 +00:00
|
|
|
rate_ctr_group_free(ul_tbf->m_ul_egprs_ctrs);
|
|
|
|
rate_ctr_group_free(ul_tbf->m_ul_gprs_ctrs);
|
2016-01-21 19:12:04 +00:00
|
|
|
} else {
|
2016-12-08 11:45:17 +00:00
|
|
|
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf);
|
|
|
|
if (tbf->is_egprs_enabled()) {
|
|
|
|
rate_ctr_group_free(dl_tbf->m_dl_egprs_ctrs);
|
|
|
|
} else {
|
|
|
|
rate_ctr_group_free(dl_tbf->m_dl_gprs_ctrs);
|
|
|
|
}
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_DL_FREED);
|
2016-01-21 19:12:04 +00:00
|
|
|
if (tbf->state_is(GPRS_RLCMAC_FLOW))
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_DL_ABORTED);
|
2016-01-21 19:12:04 +00:00
|
|
|
}
|
|
|
|
|
2013-10-16 15:55:57 +00:00
|
|
|
/* Give final measurement report */
|
|
|
|
gprs_rlcmac_rssi_rep(tbf);
|
2014-08-08 09:21:04 +00:00
|
|
|
if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
|
2015-12-28 17:49:12 +00:00
|
|
|
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf);
|
2016-01-21 19:42:40 +00:00
|
|
|
|
|
|
|
dl_tbf->abort();
|
2015-04-02 11:58:09 +00:00
|
|
|
dl_tbf->cleanup();
|
2014-08-08 09:21:04 +00:00
|
|
|
}
|
2013-10-16 15:55:57 +00:00
|
|
|
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(tbf, LOGL_INFO, "free\n");
|
2017-12-20 16:31:13 +00:00
|
|
|
tbf->stop_timers("freeing TBF");
|
2017-09-01 12:36:44 +00:00
|
|
|
/* TODO: Could/Should generate bssgp_tx_llc_discarded */
|
2013-10-16 15:55:57 +00:00
|
|
|
tbf_unlink_pdch(tbf);
|
2021-01-14 15:48:38 +00:00
|
|
|
llist_del(tbf_bts_list(tbf));
|
2013-10-27 08:50:15 +00:00
|
|
|
|
2015-05-08 10:13:08 +00:00
|
|
|
if (tbf->ms())
|
|
|
|
tbf->set_ms(NULL);
|
|
|
|
|
2016-12-08 11:45:17 +00:00
|
|
|
rate_ctr_group_free(tbf->m_ctrs);
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGP(DTBF, LOGL_DEBUG, "********** %s-TBF ends here **********\n",
|
2017-12-15 16:36:45 +00:00
|
|
|
(tbf->direction != GPRS_RLCMAC_UL_TBF) ? "DL" : "UL");
|
2013-10-16 15:55:57 +00:00
|
|
|
talloc_free(tbf);
|
|
|
|
}
|
|
|
|
|
2021-01-18 11:53:54 +00:00
|
|
|
uint16_t egprs_window_size(const struct gprs_rlcmac_bts *bts, uint8_t slots)
|
2017-12-14 14:02:33 +00:00
|
|
|
{
|
|
|
|
uint8_t num_pdch = pcu_bitcount(slots);
|
|
|
|
|
|
|
|
return OSMO_MIN((num_pdch != 1) ? (128 * num_pdch) : 192,
|
2021-01-14 13:30:03 +00:00
|
|
|
OSMO_MAX(64, (the_pcu->vty.ws_base + num_pdch * the_pcu->vty.ws_pdch) / 32 * 32));
|
2017-12-14 14:02:33 +00:00
|
|
|
}
|
|
|
|
|
2015-07-03 12:03:33 +00:00
|
|
|
int gprs_rlcmac_tbf::update()
|
2013-10-16 15:55:57 +00:00
|
|
|
{
|
2015-07-03 12:03:33 +00:00
|
|
|
int rc;
|
2013-10-16 15:55:57 +00:00
|
|
|
|
2013-10-26 15:49:36 +00:00
|
|
|
if (direction != GPRS_RLCMAC_DL_TBF)
|
2013-10-16 15:55:57 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGP(DTBF, LOGL_DEBUG, "********** DL-TBF update **********\n");
|
2017-12-15 16:36:45 +00:00
|
|
|
|
2013-10-26 15:49:36 +00:00
|
|
|
tbf_unlink_pdch(this);
|
2021-02-25 17:08:10 +00:00
|
|
|
rc = the_pcu->alloc_algorithm(bts, this, false, -1);
|
2013-10-27 09:38:31 +00:00
|
|
|
/* if no resource */
|
2013-10-16 15:55:57 +00:00
|
|
|
if (rc < 0) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_ERROR, "No resource after update???\n");
|
2021-02-25 16:21:32 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_TBF_ALLOC_FAIL);
|
2013-10-16 15:55:57 +00:00
|
|
|
return -rc;
|
|
|
|
}
|
|
|
|
|
2016-09-15 12:24:46 +00:00
|
|
|
if (is_egprs_enabled()) {
|
|
|
|
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this);
|
|
|
|
if (dl_tbf)
|
2017-12-14 14:02:33 +00:00
|
|
|
dl_tbf->set_window_size();
|
2016-09-15 12:24:46 +00:00
|
|
|
}
|
|
|
|
|
2013-10-16 15:55:57 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
if (tbf->control_ts == 0xff)
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(tbf, LOGL_INFO, "Setting Control TS %d\n",
|
2013-10-16 15:55:57 +00:00
|
|
|
tbf->first_common_ts);
|
|
|
|
else if (tbf->control_ts != tbf->first_common_ts)
|
2020-11-30 11:18:38 +00:00
|
|
|
LOGPTBF(tbf, LOGL_INFO, "Changing Control TS %d -> %d\n",
|
|
|
|
tbf->control_ts, tbf->first_common_ts);
|
2013-10-16 15:55:57 +00:00
|
|
|
tbf->control_ts = tbf->first_common_ts;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-08 09:43:53 +00:00
|
|
|
const char *gprs_rlcmac_tbf::tbf_state_name[] = {
|
2013-10-16 15:55:57 +00:00
|
|
|
"NULL",
|
|
|
|
"ASSIGN",
|
|
|
|
"FLOW",
|
|
|
|
"FINISHED",
|
|
|
|
"WAIT RELEASE",
|
|
|
|
"RELEASING",
|
|
|
|
};
|
|
|
|
|
2018-02-20 17:16:11 +00:00
|
|
|
void gprs_rlcmac_tbf::n_reset(enum tbf_counters n)
|
|
|
|
{
|
|
|
|
if (n >= N_MAX) {
|
|
|
|
LOGPTBF(this, LOGL_ERROR, "attempting to reset unknown counter %s\n",
|
|
|
|
get_value_string(tbf_counters_names, n));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-09-05 12:40:24 +00:00
|
|
|
Narr[n] = 0;
|
2018-02-20 17:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Increment counter and check for MAX value (return true if we hit it) */
|
|
|
|
bool gprs_rlcmac_tbf::n_inc(enum tbf_counters n)
|
|
|
|
{
|
|
|
|
uint8_t chk;
|
|
|
|
|
|
|
|
if (n >= N_MAX) {
|
|
|
|
LOGPTBF(this, LOGL_ERROR, "attempting to increment unknown counter %s\n",
|
|
|
|
get_value_string(tbf_counters_names, n));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-05 12:40:24 +00:00
|
|
|
Narr[n]++;
|
2018-02-20 17:16:11 +00:00
|
|
|
|
|
|
|
switch(n) {
|
|
|
|
case N3101:
|
2021-01-14 15:48:38 +00:00
|
|
|
chk = bts->n3101;
|
2018-02-20 17:16:11 +00:00
|
|
|
break;
|
|
|
|
case N3103:
|
2021-01-14 15:48:38 +00:00
|
|
|
chk = bts->n3103;
|
2018-02-20 17:16:11 +00:00
|
|
|
break;
|
|
|
|
case N3105:
|
2021-01-14 15:48:38 +00:00
|
|
|
chk = bts->n3105;
|
2018-02-20 17:16:11 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGPTBF(this, LOGL_ERROR, "unhandled counter %s\n",
|
|
|
|
get_value_string(tbf_counters_names, n));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-05 12:40:24 +00:00
|
|
|
if (Narr[n] == chk) {
|
2018-02-20 17:16:11 +00:00
|
|
|
LOGPTBF(this, LOGL_NOTICE, "%s exceeded MAX (%u)\n",
|
|
|
|
get_value_string(tbf_counters_names, n), chk);
|
|
|
|
return true;
|
2021-03-04 13:10:52 +00:00
|
|
|
} else {
|
|
|
|
LOGPTBF(this, LOGL_DEBUG, "%s %" PRIu8 " => %" PRIu8 " (< MAX %" PRIu8 ")\n",
|
|
|
|
get_value_string(tbf_counters_names, n), Narr[n] - 1, Narr[n], chk);
|
|
|
|
return false;
|
2018-02-20 17:16:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-20 16:31:13 +00:00
|
|
|
void gprs_rlcmac_tbf::t_stop(enum tbf_timers t, const char *reason)
|
|
|
|
{
|
|
|
|
if (t >= T_MAX) {
|
|
|
|
LOGPTBF(this, LOGL_ERROR, "attempting to stop unknown timer %s [%s]\n",
|
|
|
|
get_value_string(tbf_timers_names, t), reason);
|
2017-12-21 17:58:50 +00:00
|
|
|
return;
|
2017-12-20 16:31:13 +00:00
|
|
|
}
|
|
|
|
|
2019-09-05 12:40:24 +00:00
|
|
|
if (osmo_timer_pending(&Tarr[t])) {
|
2017-12-20 16:31:13 +00:00
|
|
|
LOGPTBF(this, LOGL_DEBUG, "stopping timer %s [%s]\n",
|
|
|
|
get_value_string(tbf_timers_names, t), reason);
|
2019-09-05 12:40:24 +00:00
|
|
|
osmo_timer_del(&Tarr[t]);
|
2017-12-20 16:31:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if any of T31xx timer(s) are pending */
|
|
|
|
bool gprs_rlcmac_tbf::timers_pending(enum tbf_timers t)
|
|
|
|
{
|
|
|
|
uint8_t i;
|
|
|
|
|
|
|
|
if (t != T_MAX)
|
2019-09-05 12:40:24 +00:00
|
|
|
return osmo_timer_pending(&Tarr[t]);
|
2017-12-20 16:31:13 +00:00
|
|
|
|
2017-12-20 17:05:29 +00:00
|
|
|
/* we don't start with T0 because it's internal timer which requires special handling */
|
2017-12-20 16:31:13 +00:00
|
|
|
for (i = T3169; i < T_MAX; i++)
|
2019-09-05 12:40:24 +00:00
|
|
|
if (osmo_timer_pending(&Tarr[i]))
|
2017-12-20 16:31:13 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gprs_rlcmac_tbf::stop_timers(const char *reason)
|
2013-10-16 15:55:57 +00:00
|
|
|
{
|
2017-12-20 16:31:13 +00:00
|
|
|
uint8_t i;
|
2017-12-20 17:05:29 +00:00
|
|
|
/* we start with T0 because timer reset does not require any special handling */
|
|
|
|
for (i = T0; i < T_MAX; i++)
|
2017-12-20 16:31:13 +00:00
|
|
|
t_stop((enum tbf_timers)i, reason);
|
2013-10-26 16:01:35 +00:00
|
|
|
}
|
|
|
|
|
2017-12-20 16:31:13 +00:00
|
|
|
static inline void tbf_timeout_free(struct gprs_rlcmac_tbf *tbf, enum tbf_timers t, bool run_diag)
|
|
|
|
{
|
|
|
|
LOGPTBF(tbf, LOGL_NOTICE, "%s timeout expired, freeing TBF\n",
|
|
|
|
get_value_string(tbf_timers_names, t));
|
|
|
|
|
2020-09-22 11:41:00 +00:00
|
|
|
if (run_diag) {
|
|
|
|
LOGPTBF(tbf, LOGL_NOTICE, "%s timeout expired, freeing TBF: %s\n",
|
|
|
|
get_value_string(tbf_timers_names, t), tbf->rlcmac_diag().c_str());
|
|
|
|
} else {
|
|
|
|
LOGPTBF(tbf, LOGL_NOTICE, "%s timeout expired, freeing TBF\n",
|
|
|
|
get_value_string(tbf_timers_names, t));
|
|
|
|
}
|
2017-12-20 16:31:13 +00:00
|
|
|
|
|
|
|
tbf_free(tbf);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define T_CBACK(t, diag) static void cb_##t(void *_tbf) { tbf_timeout_free((struct gprs_rlcmac_tbf *)_tbf, t, diag); }
|
|
|
|
|
|
|
|
T_CBACK(T3169, true)
|
|
|
|
T_CBACK(T3191, true)
|
|
|
|
T_CBACK(T3193, false)
|
|
|
|
T_CBACK(T3195, true)
|
|
|
|
|
2019-09-05 12:48:35 +00:00
|
|
|
void gprs_rlcmac_tbf::t_start(enum tbf_timers t, int T, const char *reason, bool force,
|
2017-12-20 17:13:29 +00:00
|
|
|
const char *file, unsigned line)
|
2017-12-20 16:31:13 +00:00
|
|
|
{
|
2021-01-18 13:05:40 +00:00
|
|
|
int current_fn = bts_current_frame_number(bts);
|
2019-09-05 12:48:35 +00:00
|
|
|
int sec;
|
|
|
|
int microsec;
|
|
|
|
struct osmo_tdef *tdef;
|
2018-04-10 12:21:11 +00:00
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
if (!(tdef = osmo_tdef_get_entry(bts->T_defs_bts, T)))
|
2021-01-14 11:01:42 +00:00
|
|
|
tdef = osmo_tdef_get_entry(bts->pcu->T_defs, T);
|
2019-09-05 12:48:35 +00:00
|
|
|
|
|
|
|
if (t >= T_MAX || !tdef) {
|
2018-04-10 12:21:11 +00:00
|
|
|
LOGPSRC(DTBF, LOGL_ERROR, file, line, "%s attempting to start unknown timer %s [%s], cur_fn=%d\n",
|
|
|
|
tbf_name(this), get_value_string(tbf_timers_names, t), reason, current_fn);
|
2017-12-21 17:58:50 +00:00
|
|
|
return;
|
2017-12-20 16:31:13 +00:00
|
|
|
}
|
|
|
|
|
2019-09-05 12:40:24 +00:00
|
|
|
if (!force && osmo_timer_pending(&Tarr[t]))
|
2017-12-20 16:31:13 +00:00
|
|
|
return;
|
|
|
|
|
2019-09-05 12:48:35 +00:00
|
|
|
switch (tdef->unit) {
|
|
|
|
case OSMO_TDEF_MS:
|
|
|
|
sec = 0;
|
|
|
|
microsec = tdef->val * 1000;
|
|
|
|
break;
|
|
|
|
case OSMO_TDEF_S:
|
|
|
|
sec = tdef->val;
|
|
|
|
microsec = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* so far only timers using MS and S */
|
|
|
|
OSMO_ASSERT(false);
|
|
|
|
}
|
|
|
|
|
2018-04-10 12:21:11 +00:00
|
|
|
LOGPSRC(DTBF, LOGL_DEBUG, file, line, "%s %sstarting timer %s [%s] with %u sec. %u microsec, cur_fn=%d\n",
|
2019-09-05 12:40:24 +00:00
|
|
|
tbf_name(this), osmo_timer_pending(&Tarr[t]) ? "re" : "",
|
2018-04-10 12:21:11 +00:00
|
|
|
get_value_string(tbf_timers_names, t), reason, sec, microsec, current_fn);
|
2017-12-20 16:31:13 +00:00
|
|
|
|
2019-09-05 12:40:24 +00:00
|
|
|
Tarr[t].data = this;
|
2017-12-20 16:31:13 +00:00
|
|
|
|
|
|
|
switch(t) {
|
2017-12-20 17:05:29 +00:00
|
|
|
case T0:
|
2019-09-05 12:40:24 +00:00
|
|
|
Tarr[t].cb = tbf_timer_cb;
|
2017-12-20 17:05:29 +00:00
|
|
|
break;
|
2017-12-20 16:31:13 +00:00
|
|
|
case T3169:
|
2019-09-05 12:40:24 +00:00
|
|
|
Tarr[t].cb = cb_T3169;
|
2017-12-20 16:31:13 +00:00
|
|
|
break;
|
|
|
|
case T3191:
|
2019-09-05 12:40:24 +00:00
|
|
|
Tarr[t].cb = cb_T3191;
|
2017-12-20 16:31:13 +00:00
|
|
|
break;
|
|
|
|
case T3193:
|
2019-09-05 12:40:24 +00:00
|
|
|
Tarr[t].cb = cb_T3193;
|
2017-12-20 16:31:13 +00:00
|
|
|
break;
|
|
|
|
case T3195:
|
2019-09-05 12:40:24 +00:00
|
|
|
Tarr[t].cb = cb_T3195;
|
2017-12-20 16:31:13 +00:00
|
|
|
break;
|
|
|
|
default:
|
2018-04-10 12:21:11 +00:00
|
|
|
LOGPSRC(DTBF, LOGL_ERROR, file, line, "%s attempting to set callback for unknown timer %s [%s], cur_fn=%d\n",
|
|
|
|
tbf_name(this), get_value_string(tbf_timers_names, t), reason, current_fn);
|
2017-12-20 16:31:13 +00:00
|
|
|
}
|
|
|
|
|
2019-09-05 12:40:24 +00:00
|
|
|
osmo_timer_schedule(&Tarr[t], sec, microsec);
|
2017-12-20 16:31:13 +00:00
|
|
|
}
|
|
|
|
|
2016-01-26 20:46:26 +00:00
|
|
|
int gprs_rlcmac_tbf::check_polling(uint32_t fn, uint8_t ts,
|
2021-02-01 17:14:23 +00:00
|
|
|
uint32_t *poll_fn_, unsigned int *rrbp_) const
|
2016-01-26 20:46:26 +00:00
|
|
|
{
|
2021-03-09 16:18:12 +00:00
|
|
|
int rc;
|
2016-01-26 20:46:26 +00:00
|
|
|
if (!is_control_ts(ts)) {
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(this, LOGL_DEBUG, "Polling cannot be "
|
2016-01-26 20:46:26 +00:00
|
|
|
"scheduled in this TS %d (first control TS %d)\n",
|
|
|
|
ts, control_ts);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (poll_state != GPRS_RLCMAC_POLL_NONE) {
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(this, LOGL_DEBUG, "Polling is already scheduled\n");
|
2016-01-26 20:46:26 +00:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2021-03-09 16:18:12 +00:00
|
|
|
if ((rc = pdch_ulc_get_next_free_rrbp_fn(trx->pdch[ts].ulc, fn, poll_fn_, rrbp_)) < 0) {
|
|
|
|
LOGPTBF(this, LOGL_DEBUG,
|
|
|
|
"(bts=%u,trx=%u,ts=%u) FN=%u No suitable free RRBP offset found!\n",
|
|
|
|
trx->bts->nr, trx->trx_no, ts, fn);
|
|
|
|
return rc;
|
|
|
|
}
|
2016-01-26 20:46:26 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-29 16:15:30 +00:00
|
|
|
void gprs_rlcmac_tbf::set_polling(uint32_t new_poll_fn, uint8_t ts, enum pdch_ulc_tbf_poll_reason reason)
|
2016-01-26 20:46:26 +00:00
|
|
|
{
|
2017-07-10 12:40:09 +00:00
|
|
|
const char *chan = "UNKNOWN";
|
|
|
|
|
|
|
|
if (state_flags & (1 << (GPRS_RLCMAC_FLAG_CCCH)))
|
|
|
|
chan = "CCCH";
|
|
|
|
|
|
|
|
if (state_flags & (1 << (GPRS_RLCMAC_FLAG_PACCH)))
|
|
|
|
chan = "PACCH";
|
|
|
|
|
|
|
|
if ((state_flags & (1 << (GPRS_RLCMAC_FLAG_PACCH))) && (state_flags & (1 << (GPRS_RLCMAC_FLAG_CCCH))))
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFDL(this, LOGL_ERROR,
|
|
|
|
"Attempt to schedule polling on %s (FN=%d, TS=%d) with both CCCH and PACCH flags set - FIXME!\n",
|
2021-03-09 16:05:21 +00:00
|
|
|
chan, new_poll_fn, ts);
|
2016-01-26 20:46:26 +00:00
|
|
|
|
|
|
|
/* schedule polling */
|
2021-03-29 16:15:30 +00:00
|
|
|
if (pdch_ulc_reserve_tbf_poll(trx->pdch[ts].ulc, new_poll_fn, this, reason) < 0) {
|
2021-03-09 16:18:12 +00:00
|
|
|
LOGPTBFDL(this, LOGL_ERROR, "Failed scheduling poll on %s (FN=%d, TS=%d)\n",
|
|
|
|
chan, poll_fn, ts);
|
|
|
|
return;
|
|
|
|
}
|
2016-01-26 20:46:26 +00:00
|
|
|
poll_state = GPRS_RLCMAC_POLL_SCHED;
|
|
|
|
poll_fn = new_poll_fn;
|
|
|
|
poll_ts = ts;
|
2017-07-10 12:40:09 +00:00
|
|
|
|
2021-03-29 16:15:30 +00:00
|
|
|
switch (reason) {
|
|
|
|
case PDCH_ULC_POLL_UL_ASS:
|
2017-07-10 12:40:09 +00:00
|
|
|
ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK;
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFDL(this, LOGL_INFO, "Scheduled UL Assignment polling on %s (FN=%d, TS=%d)\n",
|
|
|
|
chan, poll_fn, poll_ts);
|
2017-07-10 12:40:09 +00:00
|
|
|
break;
|
2021-03-29 16:15:30 +00:00
|
|
|
case PDCH_ULC_POLL_DL_ASS:
|
2017-07-10 12:40:09 +00:00
|
|
|
dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK;
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFDL(this, LOGL_INFO, "Scheduled DL Assignment polling on %s (FN=%d, TS=%d)\n",
|
|
|
|
chan, poll_fn, poll_ts);
|
2017-07-10 12:40:09 +00:00
|
|
|
break;
|
2021-03-29 16:15:30 +00:00
|
|
|
case PDCH_ULC_POLL_UL_ACK:
|
2017-07-10 12:40:09 +00:00
|
|
|
ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK;
|
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG, "Scheduled UL Acknowledgement polling on %s (FN=%d, TS=%d)\n",
|
|
|
|
chan, poll_fn, poll_ts);
|
2017-07-10 12:40:09 +00:00
|
|
|
break;
|
2021-03-29 16:15:30 +00:00
|
|
|
case PDCH_ULC_POLL_DL_ACK:
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBFDL(this, LOGL_DEBUG, "Scheduled DL Acknowledgement polling on %s (FN=%d, TS=%d)\n",
|
|
|
|
chan, poll_fn, poll_ts);
|
2017-07-10 12:40:09 +00:00
|
|
|
break;
|
2021-03-29 16:15:30 +00:00
|
|
|
case PDCH_ULC_POLL_CELL_CHG_CONTINUE:
|
2021-02-01 13:52:48 +00:00
|
|
|
LOGPTBFDL(this, LOGL_DEBUG, "Scheduled 'Packet Cell Change Continue' polling on %s (FN=%d, TS=%d)\n",
|
|
|
|
chan, poll_fn, poll_ts);
|
|
|
|
break;
|
2017-07-10 12:40:09 +00:00
|
|
|
}
|
2016-01-26 20:46:26 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 16:15:30 +00:00
|
|
|
void gprs_rlcmac_tbf::poll_timeout(enum pdch_ulc_tbf_poll_reason reason)
|
2013-10-26 18:12:59 +00:00
|
|
|
{
|
2019-12-23 11:41:34 +00:00
|
|
|
uint16_t pgroup;
|
2017-07-07 12:29:36 +00:00
|
|
|
gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(this);
|
|
|
|
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(this, LOGL_NOTICE, "poll timeout for FN=%d, TS=%d (curr FN %d)\n",
|
2021-01-14 15:48:38 +00:00
|
|
|
poll_fn, poll_ts, bts_current_frame_number(bts));
|
2013-10-26 18:12:59 +00:00
|
|
|
|
|
|
|
poll_state = GPRS_RLCMAC_POLL_NONE;
|
|
|
|
|
2021-03-29 16:15:30 +00:00
|
|
|
if (ul_tbf && ul_tbf->handle_ctrl_ack(reason)) {
|
2017-07-07 12:29:36 +00:00
|
|
|
if (!ul_tbf->ctrl_ack_to_toggle()) {
|
2020-09-22 11:41:00 +00:00
|
|
|
LOGPTBF(this, LOGL_NOTICE,
|
|
|
|
"Timeout for polling PACKET CONTROL ACK for PACKET UPLINK ACK: %s\n",
|
|
|
|
rlcmac_diag().c_str());
|
2013-10-26 18:12:59 +00:00
|
|
|
}
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_RLC_ACK_TIMEDOUT);
|
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PUAN_POLL_TIMEDOUT);
|
2013-10-26 18:12:59 +00:00
|
|
|
if (state_is(GPRS_RLCMAC_FINISHED)) {
|
2018-02-20 17:16:11 +00:00
|
|
|
if (ul_tbf->n_inc(N3103)) {
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PUAN_POLL_FAILED);
|
2018-01-12 14:48:12 +00:00
|
|
|
TBF_SET_STATE(ul_tbf, GPRS_RLCMAC_RELEASING);
|
2019-09-05 12:48:35 +00:00
|
|
|
T_START(ul_tbf, T3169, 3169, "MAX N3103 reached", false);
|
2013-10-26 18:12:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* reschedule UL ack */
|
2014-08-07 11:03:35 +00:00
|
|
|
ul_tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK;
|
2013-10-26 18:12:59 +00:00
|
|
|
}
|
2015-07-07 07:33:29 +00:00
|
|
|
|
2013-10-26 18:12:59 +00:00
|
|
|
} else if (ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) {
|
|
|
|
if (!(state_flags & (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS))) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_NOTICE,
|
2020-09-22 11:41:00 +00:00
|
|
|
"Timeout for polling PACKET CONTROL ACK for PACKET UPLINK ASSIGNMENT: %s\n",
|
|
|
|
rlcmac_diag().c_str());
|
2018-01-19 17:22:25 +00:00
|
|
|
state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS);
|
2013-10-26 18:12:59 +00:00
|
|
|
}
|
|
|
|
ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE;
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_TIMEDOUT);
|
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PUA_POLL_TIMEDOUT);
|
2018-02-20 17:16:11 +00:00
|
|
|
if (n_inc(N3105)) {
|
2018-01-12 14:48:12 +00:00
|
|
|
TBF_SET_STATE(this, GPRS_RLCMAC_RELEASING);
|
2019-09-05 12:48:35 +00:00
|
|
|
T_START(this, T3195, 3195, "MAX N3105 reached", true);
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_FAILED);
|
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PUA_POLL_FAILED);
|
2013-10-26 18:12:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* reschedule UL assignment */
|
|
|
|
ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
|
|
|
|
} else if (dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) {
|
|
|
|
if (!(state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS))) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_NOTICE,
|
2020-09-22 11:41:00 +00:00
|
|
|
"Timeout for polling PACKET CONTROL ACK for PACKET DOWNLINK ASSIGNMENT: %s\n",
|
|
|
|
rlcmac_diag().c_str());
|
2013-10-26 18:12:59 +00:00
|
|
|
state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS);
|
|
|
|
}
|
|
|
|
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_TIMEDOUT);
|
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PDA_POLL_TIMEDOUT);
|
2018-02-20 17:16:11 +00:00
|
|
|
if (n_inc(N3105)) {
|
2018-01-12 14:48:12 +00:00
|
|
|
TBF_SET_STATE(this, GPRS_RLCMAC_RELEASING);
|
2019-09-05 12:48:35 +00:00
|
|
|
T_START(this, T3195, 3195, "MAX N3105 reached", true);
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_FAILED);
|
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PDA_POLL_FAILED);
|
2013-10-26 18:12:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* reschedule DL assignment */
|
|
|
|
dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS;
|
2021-02-01 13:52:48 +00:00
|
|
|
} else if (m_ms->nacc && m_ms->nacc->fi->state == NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK &&
|
|
|
|
m_ms->nacc->continue_poll_fn == poll_fn && m_ms->nacc->continue_poll_ts == poll_ts) {
|
|
|
|
/* Timeout waiting for CTRL ACK acking Pkt Cell Change Continue */
|
|
|
|
osmo_fsm_inst_dispatch(m_ms->nacc->fi, NACC_EV_TIMEOUT_CELL_CHG_CONTINUE, NULL);
|
|
|
|
return;
|
2013-10-26 18:12:59 +00:00
|
|
|
} else if (direction == GPRS_RLCMAC_DL_TBF) {
|
2015-12-28 17:49:12 +00:00
|
|
|
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this);
|
2014-08-07 11:03:35 +00:00
|
|
|
|
|
|
|
if (!(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_NOTICE,
|
2020-09-22 11:41:00 +00:00
|
|
|
"Timeout for polling PACKET DOWNLINK ACK: %s\n",
|
|
|
|
dl_tbf->rlcmac_diag().c_str());
|
2014-08-07 11:03:35 +00:00
|
|
|
dl_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
|
2013-10-26 18:12:59 +00:00
|
|
|
}
|
2018-02-20 17:16:11 +00:00
|
|
|
|
2015-07-07 07:33:29 +00:00
|
|
|
if (dl_tbf->state_is(GPRS_RLCMAC_RELEASING))
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_RLC_REL_TIMEDOUT);
|
2016-11-10 12:46:30 +00:00
|
|
|
else {
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_RLC_ACK_TIMEDOUT);
|
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PDAN_POLL_TIMEDOUT);
|
2016-11-10 12:46:30 +00:00
|
|
|
}
|
2018-02-20 17:16:11 +00:00
|
|
|
|
|
|
|
if (dl_tbf->n_inc(N3105)) {
|
2018-01-12 14:48:12 +00:00
|
|
|
TBF_SET_STATE(dl_tbf, GPRS_RLCMAC_RELEASING);
|
2019-09-05 12:48:35 +00:00
|
|
|
T_START(dl_tbf, T3195, 3195, "MAX N3105 reached", true);
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PDAN_POLL_FAILED);
|
|
|
|
bts_do_rate_ctr_inc(bts, CTR_RLC_ACK_FAILED);
|
2013-10-26 18:12:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* resend IMM.ASS on CCCH on timeout */
|
2014-08-07 11:03:35 +00:00
|
|
|
if ((dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))
|
|
|
|
&& !(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK))) {
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(dl_tbf, LOGL_DEBUG, "Re-send dowlink assignment on PCH (IMSI=%s)\n",
|
2015-05-21 09:07:16 +00:00
|
|
|
imsi());
|
2013-10-26 18:12:59 +00:00
|
|
|
/* send immediate assignment */
|
2019-12-23 11:41:34 +00:00
|
|
|
if ((pgroup = imsi2paging_group(imsi())) > 999)
|
|
|
|
LOGPTBF(dl_tbf, LOGL_ERROR, "IMSI to paging group failed! (%s)\n", imsi());
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_snd_dl_ass(dl_tbf->bts, dl_tbf, false, pgroup);
|
2014-08-07 13:49:21 +00:00
|
|
|
dl_tbf->m_wait_confirm = 1;
|
2013-10-26 18:12:59 +00:00
|
|
|
}
|
|
|
|
} else
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_ERROR, "Poll Timeout, but no event!\n");
|
2013-10-26 18:12:59 +00:00
|
|
|
}
|
|
|
|
|
2020-10-23 16:41:40 +00:00
|
|
|
int gprs_rlcmac_tbf::setup(int8_t use_trx, bool single_slot)
|
2013-10-16 16:09:19 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2014-07-30 11:25:19 +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
|
|
|
if (ms_mode(m_ms) != GPRS)
|
2020-10-23 16:41:40 +00:00
|
|
|
enable_egprs();
|
2015-09-28 16:54:32 +00:00
|
|
|
|
2020-10-23 16:41:40 +00:00
|
|
|
m_created_ts = time(NULL);
|
2013-10-16 16:09:19 +00:00
|
|
|
/* select algorithm */
|
2021-02-25 17:08:10 +00:00
|
|
|
rc = the_pcu->alloc_algorithm(bts, this, single_slot, use_trx);
|
2013-10-27 09:38:31 +00:00
|
|
|
/* if no resource */
|
2013-10-16 16:09:19 +00:00
|
|
|
if (rc < 0) {
|
2021-02-25 16:21:10 +00:00
|
|
|
LOGPTBF(this, LOGL_NOTICE,
|
|
|
|
"Timeslot Allocation failed: trx = %d, single_slot = %d\n",
|
|
|
|
use_trx, single_slot);
|
2021-02-25 16:21:32 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_TBF_ALLOC_FAIL);
|
2014-07-16 16:54:10 +00:00
|
|
|
return -1;
|
2013-10-16 16:09:19 +00:00
|
|
|
}
|
|
|
|
/* assign control ts */
|
2020-10-23 16:41:40 +00:00
|
|
|
rc = tbf_assign_control_ts(this);
|
2013-10-27 09:38:31 +00:00
|
|
|
/* if no resource */
|
2013-10-16 16:09:19 +00:00
|
|
|
if (rc < 0) {
|
2014-07-16 16:54:10 +00:00
|
|
|
return -1;
|
2013-10-16 16:09:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set timestamp */
|
2020-10-23 16:41:40 +00:00
|
|
|
osmo_clock_gettime(CLOCK_MONOTONIC, &meas.rssi_tv);
|
2013-10-16 16:09:19 +00:00
|
|
|
|
2020-10-23 16:41:40 +00:00
|
|
|
LOGPTBF(this, LOGL_INFO,
|
2018-01-19 17:22:25 +00:00
|
|
|
"Allocated: trx = %d, ul_slots = %02x, dl_slots = %02x\n",
|
2020-10-23 16:41:40 +00:00
|
|
|
this->trx->trx_no, ul_slots(), dl_slots());
|
2015-07-10 08:41:36 +00:00
|
|
|
|
2020-10-23 16:41:40 +00:00
|
|
|
m_ctrs = rate_ctr_group_alloc(this, &tbf_ctrg_desc, next_tbf_ctr_group_id++);
|
|
|
|
if (!m_ctrs) {
|
|
|
|
LOGPTBF(this, LOGL_ERROR, "Couldn't allocate TBF counters\n");
|
2017-07-11 22:46:36 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2016-12-08 11:45:17 +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
|
|
|
ms_attach_tbf(m_ms, this);
|
2020-10-23 16:41:40 +00:00
|
|
|
|
2014-07-16 16:54:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-26 15:56:15 +00:00
|
|
|
static void tbf_timer_cb(void *_tbf)
|
2013-10-16 16:09:19 +00:00
|
|
|
{
|
|
|
|
struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)_tbf;
|
2013-10-26 15:56:15 +00:00
|
|
|
tbf->handle_timeout();
|
|
|
|
}
|
2013-10-16 16:09:19 +00:00
|
|
|
|
2013-10-26 15:56:15 +00:00
|
|
|
void gprs_rlcmac_tbf::handle_timeout()
|
|
|
|
{
|
2021-01-18 13:05:40 +00:00
|
|
|
int current_fn = bts_current_frame_number(bts);
|
2018-04-10 12:21:11 +00:00
|
|
|
|
|
|
|
LOGPTBF(this, LOGL_DEBUG, "timer 0 expired. cur_fn=%d\n", current_fn);
|
2017-12-20 16:31:13 +00:00
|
|
|
|
|
|
|
/* assignment */
|
|
|
|
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) {
|
|
|
|
if (state_is(GPRS_RLCMAC_ASSIGN)) {
|
|
|
|
LOGPTBF(this, LOGL_NOTICE, "releasing due to PACCH assignment timeout.\n");
|
|
|
|
tbf_free(this);
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
LOGPTBF(this, LOGL_ERROR, "Error: TBF is not in assign state\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) {
|
|
|
|
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this);
|
|
|
|
dl_tbf->m_wait_confirm = 0;
|
|
|
|
if (dl_tbf->state_is(GPRS_RLCMAC_ASSIGN)) {
|
|
|
|
tbf_assign_control_ts(dl_tbf);
|
|
|
|
|
|
|
|
if (!dl_tbf->upgrade_to_multislot) {
|
|
|
|
/* change state to FLOW, so scheduler
|
|
|
|
* will start transmission */
|
2018-01-12 14:48:12 +00:00
|
|
|
TBF_SET_STATE(dl_tbf, GPRS_RLCMAC_FLOW);
|
2017-12-20 16:31:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This tbf can be upgraded to use multiple DL
|
|
|
|
* timeslots and now that there is already one
|
|
|
|
* slot assigned send another DL assignment via
|
|
|
|
* PDCH. */
|
|
|
|
|
|
|
|
/* keep to flags */
|
|
|
|
dl_tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
|
|
|
|
|
|
|
|
dl_tbf->update();
|
|
|
|
|
|
|
|
dl_tbf->trigger_ass(dl_tbf);
|
|
|
|
} else
|
|
|
|
LOGPTBF(dl_tbf, LOGL_NOTICE, "Continue flow after IMM.ASS confirm\n");
|
2013-10-16 16:09:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-22 11:41:00 +00:00
|
|
|
std::string gprs_rlcmac_tbf::rlcmac_diag()
|
2013-10-16 16:09:19 +00:00
|
|
|
{
|
2020-09-22 11:41:00 +00:00
|
|
|
std::ostringstream os;
|
|
|
|
os << "|";
|
2013-10-16 16:09:19 +00:00
|
|
|
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)))
|
2020-09-22 11:41:00 +00:00
|
|
|
os << "Assignment was on CCCH|";
|
2013-10-16 16:09:19 +00:00
|
|
|
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH)))
|
2020-09-22 11:41:00 +00:00
|
|
|
os << "Assignment was on PACCH|";
|
2013-10-16 16:09:19 +00:00
|
|
|
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_UL_DATA)))
|
2020-09-22 11:41:00 +00:00
|
|
|
os << "Uplink data was received|";
|
2013-10-16 16:09:19 +00:00
|
|
|
else if (direction == GPRS_RLCMAC_UL_TBF)
|
2020-09-22 11:41:00 +00:00
|
|
|
os << "No uplink data received yet|";
|
2013-10-16 16:09:19 +00:00
|
|
|
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK)))
|
2020-09-22 11:41:00 +00:00
|
|
|
os << "Downlink ACK was received|";
|
2013-10-16 16:09:19 +00:00
|
|
|
else if (direction == GPRS_RLCMAC_DL_TBF)
|
2020-09-22 11:41:00 +00:00
|
|
|
os << "No downlink ACK received yet|";
|
2013-10-16 16:09:19 +00:00
|
|
|
|
2020-09-22 11:41:00 +00:00
|
|
|
return os.str();
|
2013-10-16 16:09:19 +00:00
|
|
|
}
|
|
|
|
|
2016-01-22 16:25:38 +00:00
|
|
|
struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts)
|
2013-10-26 18:45:35 +00:00
|
|
|
{
|
|
|
|
struct msgb *msg;
|
2015-05-22 13:47:55 +00:00
|
|
|
struct gprs_rlcmac_dl_tbf *new_dl_tbf = NULL;
|
2020-02-03 16:18:03 +00:00
|
|
|
RlcMacDownlink_t *mac_control_block = NULL;
|
2013-11-24 21:52:10 +00:00
|
|
|
int poll_ass_dl = 1;
|
2016-01-26 20:46:26 +00:00
|
|
|
unsigned int rrbp = 0;
|
|
|
|
uint32_t new_poll_fn = 0;
|
|
|
|
int rc;
|
2016-01-29 15:39:21 +00:00
|
|
|
bool old_tfi_is_valid = is_tfi_assigned();
|
2013-10-26 18:45:35 +00:00
|
|
|
|
2016-01-22 16:41:33 +00:00
|
|
|
if (direction == GPRS_RLCMAC_DL_TBF && !is_control_ts(ts)) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_NOTICE,
|
2018-10-06 08:42:58 +00:00
|
|
|
"Cannot poll for downlink assignment, because MS cannot reply. (TS=%d, first common TS=%d)\n",
|
2018-01-19 17:22:25 +00:00
|
|
|
ts, first_common_ts);
|
2013-10-26 18:45:35 +00:00
|
|
|
poll_ass_dl = 0;
|
|
|
|
}
|
|
|
|
if (poll_ass_dl) {
|
2016-01-26 20:46:26 +00:00
|
|
|
if (poll_state == GPRS_RLCMAC_POLL_SCHED &&
|
|
|
|
ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK)
|
|
|
|
{
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_DEBUG,
|
2017-12-15 16:36:45 +00:00
|
|
|
"Polling is already scheduled, so we must wait for the uplink assignment...\n");
|
2013-10-26 18:45:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-01-26 20:46:26 +00:00
|
|
|
rc = check_polling(fn, ts, &new_poll_fn, &rrbp);
|
|
|
|
if (rc < 0)
|
|
|
|
return NULL;
|
2013-10-26 18:45:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* on uplink TBF we get the downlink TBF to be assigned. */
|
|
|
|
if (direction == GPRS_RLCMAC_UL_TBF) {
|
2015-12-28 17:49:12 +00:00
|
|
|
gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(this);
|
2014-08-07 12:48:20 +00:00
|
|
|
|
2013-10-26 18:45:35 +00:00
|
|
|
/* be sure to check first, if contention resolution is done,
|
|
|
|
* otherwise we cannot send the assignment yet */
|
2014-08-07 13:49:21 +00:00
|
|
|
if (!ul_tbf->m_contention_resolution_done) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_DEBUG,
|
|
|
|
"Cannot assign DL TBF now, because contention resolution is not finished.\n");
|
2013-10-26 18:45:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2014-08-15 14:52:09 +00:00
|
|
|
}
|
|
|
|
|
2015-05-22 13:47:55 +00:00
|
|
|
if (ms())
|
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
|
|
|
new_dl_tbf = ms_dl_tbf(ms());
|
2015-05-22 13:47:55 +00:00
|
|
|
|
2014-08-07 12:48:20 +00:00
|
|
|
if (!new_dl_tbf) {
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBFDL(this, LOGL_ERROR,
|
|
|
|
"We have a schedule for downlink assignment, but there is no downlink TBF\n");
|
2013-10-26 18:45:35 +00:00
|
|
|
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-01-29 15:39:21 +00:00
|
|
|
if (new_dl_tbf == as_dl_tbf(this))
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_DEBUG, "New and old TBF are the same.\n");
|
2016-01-29 15:39:21 +00:00
|
|
|
|
|
|
|
if (old_tfi_is_valid && !new_dl_tbf->is_tlli_valid()) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGPTBF(this, LOGL_ERROR,
|
|
|
|
"The old TFI is not assigned and there is no TLLI. New TBF %s\n",
|
|
|
|
new_dl_tbf->name());
|
2016-01-29 15:39:21 +00:00
|
|
|
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-12-26 17:32:00 +00:00
|
|
|
new_dl_tbf->was_releasing = was_releasing;
|
2020-08-21 12:53:32 +00:00
|
|
|
msg = msgb_alloc(GSM_MACBLOCK_LEN, "rlcmac_dl_ass");
|
2013-10-26 18:45:35 +00:00
|
|
|
if (!msg)
|
|
|
|
return NULL;
|
2020-08-21 12:45:09 +00:00
|
|
|
|
|
|
|
/* Initialize a bit vector that uses allocated msgb as the data buffer.
|
|
|
|
* Old G++ does not support non-trivial designated initializers. Sigh. */
|
|
|
|
struct bitvec bv = { };
|
|
|
|
bv.data = msgb_put(msg, GSM_MACBLOCK_LEN);
|
|
|
|
bv.data_len = GSM_MACBLOCK_LEN;
|
|
|
|
bitvec_unhex(&bv, DUMMY_VEC);
|
|
|
|
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(new_dl_tbf, LOGL_INFO, "start Packet Downlink Assignment (PACCH)\n");
|
2020-02-03 16:18:03 +00:00
|
|
|
mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
|
2016-01-29 15:39:21 +00:00
|
|
|
Encoding::write_packet_downlink_assignment(mac_control_block,
|
|
|
|
old_tfi_is_valid, m_tfi, (direction == GPRS_RLCMAC_DL_TBF),
|
|
|
|
new_dl_tbf, poll_ass_dl, rrbp,
|
2021-02-09 17:47:34 +00:00
|
|
|
bts_get_ms_pwr_alpha(new_dl_tbf->bts), the_pcu->vty.gamma, -1, 0,
|
2016-01-07 15:04:29 +00:00
|
|
|
is_egprs_enabled());
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGP(DTBF, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n");
|
2020-08-21 12:45:09 +00:00
|
|
|
rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block);
|
2020-02-03 16:18:03 +00:00
|
|
|
if (rc < 0) {
|
2020-12-18 18:03:42 +00:00
|
|
|
LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Downlink Ass failed (%d)\n", rc);
|
2020-02-03 16:18:03 +00:00
|
|
|
goto free_ret;
|
|
|
|
}
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGP(DTBF, LOGL_DEBUG, "------------------------- TX : Packet Downlink Assignment -------------------------\n");
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PKT_DL_ASSIGNMENT);
|
2013-10-26 18:45:35 +00:00
|
|
|
|
|
|
|
if (poll_ass_dl) {
|
2021-03-29 16:15:30 +00:00
|
|
|
set_polling(new_poll_fn, ts, PDCH_ULC_POLL_DL_ASS);
|
2013-10-26 18:45:35 +00:00
|
|
|
} else {
|
|
|
|
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
|
2018-01-12 14:48:12 +00:00
|
|
|
TBF_SET_STATE(new_dl_tbf, GPRS_RLCMAC_FLOW);
|
2014-08-07 12:48:20 +00:00
|
|
|
tbf_assign_control_ts(new_dl_tbf);
|
2013-10-26 18:45:35 +00:00
|
|
|
/* stop pending assignment timer */
|
2017-12-20 17:05:29 +00:00
|
|
|
new_dl_tbf->t_stop(T0, "assignment (DL-TBF)");
|
2013-10-26 18:45:35 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-02-03 16:18:03 +00:00
|
|
|
talloc_free(mac_control_block);
|
2013-10-26 18:45:35 +00:00
|
|
|
return msg;
|
2020-02-03 16:18:03 +00:00
|
|
|
|
|
|
|
free_ret:
|
|
|
|
talloc_free(mac_control_block);
|
|
|
|
msgb_free(msg);
|
|
|
|
return NULL;
|
2013-10-26 18:45:35 +00:00
|
|
|
}
|
|
|
|
|
2016-11-11 11:45:10 +00:00
|
|
|
struct msgb *gprs_rlcmac_tbf::create_packet_access_reject()
|
|
|
|
{
|
|
|
|
struct msgb *msg;
|
|
|
|
|
2020-08-21 12:53:32 +00:00
|
|
|
msg = msgb_alloc(GSM_MACBLOCK_LEN, "rlcmac_ul_ass_rej");
|
2016-11-11 11:45:10 +00:00
|
|
|
|
2020-08-21 12:53:32 +00:00
|
|
|
bitvec *packet_access_rej = bitvec_alloc(GSM_MACBLOCK_LEN, tall_pcu_ctx);
|
2016-11-11 11:45:10 +00:00
|
|
|
|
2019-02-18 19:42:42 +00:00
|
|
|
bitvec_unhex(packet_access_rej, DUMMY_VEC);
|
2016-11-11 11:45:10 +00:00
|
|
|
|
|
|
|
Encoding::write_packet_access_reject(
|
|
|
|
packet_access_rej, tlli());
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PKT_ACCESS_REJ);
|
2016-11-25 14:23:36 +00:00
|
|
|
|
2020-08-21 12:53:32 +00:00
|
|
|
bitvec_pack(packet_access_rej, msgb_put(msg, GSM_MACBLOCK_LEN));
|
2016-11-11 11:45:10 +00:00
|
|
|
|
|
|
|
bitvec_free(packet_access_rej);
|
|
|
|
ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE;
|
|
|
|
|
2017-01-24 07:06:08 +00:00
|
|
|
/* Start Tmr only if it is UL TBF */
|
|
|
|
if (direction == GPRS_RLCMAC_UL_TBF)
|
2019-09-05 12:48:35 +00:00
|
|
|
T_START(this, T0, -2000, "reject (PACCH)", true);
|
2017-01-24 07:06:08 +00:00
|
|
|
|
2016-11-11 11:45:10 +00:00
|
|
|
return msg;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-01-22 16:25:38 +00:00
|
|
|
struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn, uint8_t ts)
|
2013-10-26 19:20:51 +00:00
|
|
|
{
|
2020-02-03 16:18:03 +00:00
|
|
|
struct msgb *msg = NULL;
|
2015-05-22 13:47:55 +00:00
|
|
|
struct gprs_rlcmac_ul_tbf *new_tbf = NULL;
|
2020-02-03 16:18:03 +00:00
|
|
|
RlcMacDownlink_t *mac_control_block = NULL;
|
2016-01-26 20:46:26 +00:00
|
|
|
int rc;
|
|
|
|
unsigned int rrbp;
|
|
|
|
uint32_t new_poll_fn;
|
2013-10-26 19:20:51 +00:00
|
|
|
|
2016-01-26 20:46:26 +00:00
|
|
|
if (poll_state == GPRS_RLCMAC_POLL_SCHED &&
|
|
|
|
ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) {
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBFUL(this, LOGL_DEBUG,
|
|
|
|
"Polling is already scheduled, so we must wait for the uplink assignment...\n");
|
2020-02-08 19:48:03 +00:00
|
|
|
return NULL;
|
2013-10-26 19:20:51 +00:00
|
|
|
}
|
2016-01-26 20:46:26 +00:00
|
|
|
|
|
|
|
rc = check_polling(fn, ts, &new_poll_fn, &rrbp);
|
|
|
|
if (rc < 0)
|
|
|
|
return NULL;
|
2013-10-26 19:20:51 +00:00
|
|
|
|
2015-05-22 13:47:55 +00:00
|
|
|
if (ms())
|
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
|
|
|
new_tbf = ms_ul_tbf(ms());
|
2013-10-26 19:20:51 +00:00
|
|
|
if (!new_tbf) {
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBFUL(this, LOGL_ERROR,
|
|
|
|
"We have a schedule for uplink assignment, but there is no uplink TBF\n");
|
2013-10-26 19:20:51 +00:00
|
|
|
ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-08-21 12:53:32 +00:00
|
|
|
msg = msgb_alloc(GSM_MACBLOCK_LEN, "rlcmac_ul_ass");
|
2013-10-26 19:20:51 +00:00
|
|
|
if (!msg)
|
|
|
|
return NULL;
|
2020-08-21 12:45:09 +00:00
|
|
|
|
|
|
|
/* Initialize a bit vector that uses allocated msgb as the data buffer.
|
|
|
|
* Old G++ does not support non-trivial designated initializers. Sigh. */
|
|
|
|
struct bitvec bv = { };
|
|
|
|
bv.data = msgb_put(msg, GSM_MACBLOCK_LEN);
|
|
|
|
bv.data_len = GSM_MACBLOCK_LEN;
|
|
|
|
bitvec_unhex(&bv, DUMMY_VEC);
|
|
|
|
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(new_tbf, LOGL_INFO, "start Packet Uplink Assignment (PACCH)\n");
|
encoding: use CSN.1 codec to generate Packet Uplink Assignment
It's quite odd to see that in write_packet_downlink_assignment()
we initialize an 'RlcMacDownlink_t', so then the caller can use
the power of CSN.1 codec to generate the final sequence of bytes
to be transmitted, while in write_packet_uplink_assignment() we
already compose the final RLC/MAC message straight away using
the low-level bitvec API (like bitvec_write_field()).
I guess the reason is that at the time of writing this code, the
CSN.1 codec was not stable enough, so it was safer to generate
the message 'by hand'. This would also explain why we *decode*
the final RLC/MAC message in create_ul_ass() right after encoding.
Rewrite write_packet_uplink_assignment(), so now it initializes
a caller-provided 'RlcMacDownlink_t' structure. Given that it's
allocated on heap using talloc_zero(), do not initialize presence
indicators of fields that are not present in the message.
This would facilitate handling of frequency hopping parameters
in the upcoming changes, in particular we can now introduce a
function that would compose Frequency Parameters IE for both
write_packet_{downlink,uplink}_assignment().
Tested manually by running a GPRS-enabled network, as well as by
running test cases from ttcn3-pcu-test => no regressions observed.
Change-Id: I2850b91e0043cdca8ae7498a5fc727eeedd029b6
Related: SYS#4868, OS#4547
2020-08-21 19:05:28 +00:00
|
|
|
mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
|
|
|
|
Encoding::write_packet_uplink_assignment(mac_control_block, m_tfi,
|
2015-05-20 10:06:46 +00:00
|
|
|
(direction == GPRS_RLCMAC_DL_TBF), tlli(),
|
2021-02-09 17:47:34 +00:00
|
|
|
is_tlli_valid(), new_tbf, 1, rrbp, bts_get_ms_pwr_alpha(new_tbf->bts),
|
2021-01-14 11:53:53 +00:00
|
|
|
the_pcu->vty.gamma, -1, is_egprs_enabled());
|
2020-02-03 16:18:03 +00:00
|
|
|
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGP(DTBF, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
|
encoding: use CSN.1 codec to generate Packet Uplink Assignment
It's quite odd to see that in write_packet_downlink_assignment()
we initialize an 'RlcMacDownlink_t', so then the caller can use
the power of CSN.1 codec to generate the final sequence of bytes
to be transmitted, while in write_packet_uplink_assignment() we
already compose the final RLC/MAC message straight away using
the low-level bitvec API (like bitvec_write_field()).
I guess the reason is that at the time of writing this code, the
CSN.1 codec was not stable enough, so it was safer to generate
the message 'by hand'. This would also explain why we *decode*
the final RLC/MAC message in create_ul_ass() right after encoding.
Rewrite write_packet_uplink_assignment(), so now it initializes
a caller-provided 'RlcMacDownlink_t' structure. Given that it's
allocated on heap using talloc_zero(), do not initialize presence
indicators of fields that are not present in the message.
This would facilitate handling of frequency hopping parameters
in the upcoming changes, in particular we can now introduce a
function that would compose Frequency Parameters IE for both
write_packet_{downlink,uplink}_assignment().
Tested manually by running a GPRS-enabled network, as well as by
running test cases from ttcn3-pcu-test => no regressions observed.
Change-Id: I2850b91e0043cdca8ae7498a5fc727eeedd029b6
Related: SYS#4868, OS#4547
2020-08-21 19:05:28 +00:00
|
|
|
rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block);
|
2020-02-03 16:18:03 +00:00
|
|
|
if (rc < 0) {
|
encoding: use CSN.1 codec to generate Packet Uplink Assignment
It's quite odd to see that in write_packet_downlink_assignment()
we initialize an 'RlcMacDownlink_t', so then the caller can use
the power of CSN.1 codec to generate the final sequence of bytes
to be transmitted, while in write_packet_uplink_assignment() we
already compose the final RLC/MAC message straight away using
the low-level bitvec API (like bitvec_write_field()).
I guess the reason is that at the time of writing this code, the
CSN.1 codec was not stable enough, so it was safer to generate
the message 'by hand'. This would also explain why we *decode*
the final RLC/MAC message in create_ul_ass() right after encoding.
Rewrite write_packet_uplink_assignment(), so now it initializes
a caller-provided 'RlcMacDownlink_t' structure. Given that it's
allocated on heap using talloc_zero(), do not initialize presence
indicators of fields that are not present in the message.
This would facilitate handling of frequency hopping parameters
in the upcoming changes, in particular we can now introduce a
function that would compose Frequency Parameters IE for both
write_packet_{downlink,uplink}_assignment().
Tested manually by running a GPRS-enabled network, as well as by
running test cases from ttcn3-pcu-test => no regressions observed.
Change-Id: I2850b91e0043cdca8ae7498a5fc727eeedd029b6
Related: SYS#4868, OS#4547
2020-08-21 19:05:28 +00:00
|
|
|
LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Uplink Ass failed (%d)\n", rc);
|
2020-02-03 16:18:03 +00:00
|
|
|
goto free_ret;
|
|
|
|
}
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGP(DTBF, LOGL_DEBUG, "------------------------- TX : Packet Uplink Assignment -------------------------\n");
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_PKT_UL_ASSIGNMENT);
|
2013-10-26 19:20:51 +00:00
|
|
|
|
2021-03-29 16:15:30 +00:00
|
|
|
set_polling(new_poll_fn, ts, PDCH_ULC_POLL_UL_ASS);
|
2013-10-26 19:20:51 +00:00
|
|
|
|
2020-02-03 16:18:03 +00:00
|
|
|
talloc_free(mac_control_block);
|
2013-10-26 19:20:51 +00:00
|
|
|
return msg;
|
2020-02-03 16:18:03 +00:00
|
|
|
|
|
|
|
free_ret:
|
|
|
|
talloc_free(mac_control_block);
|
|
|
|
msgb_free(msg);
|
|
|
|
return NULL;
|
2013-10-26 19:20:51 +00:00
|
|
|
}
|
|
|
|
|
2015-09-01 09:20:29 +00:00
|
|
|
int gprs_rlcmac_tbf::establish_dl_tbf_on_pacch()
|
|
|
|
{
|
|
|
|
struct gprs_rlcmac_dl_tbf *new_tbf = NULL;
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
bts_do_rate_ctr_inc(bts, CTR_TBF_REUSED);
|
2015-09-01 09:20:29 +00:00
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
new_tbf = tbf_alloc_dl_tbf(bts, ms(),
|
2020-05-08 16:15:59 +00:00
|
|
|
this->trx->trx_no, false);
|
2015-09-01 09:20:29 +00:00
|
|
|
|
|
|
|
if (!new_tbf) {
|
2018-01-19 17:22:25 +00:00
|
|
|
LOGP(DTBF, LOGL_NOTICE, "No PDCH resource\n");
|
2015-09-01 09:20:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-12-15 16:36:45 +00:00
|
|
|
LOGPTBF(this, LOGL_DEBUG, "Trigger downlink assignment on PACCH\n");
|
2017-07-07 16:25:41 +00:00
|
|
|
new_tbf->trigger_ass(this);
|
2015-09-01 09:20:29 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-02-01 17:14:23 +00:00
|
|
|
const char *tbf_name(const gprs_rlcmac_tbf *tbf)
|
2013-10-27 15:39:36 +00:00
|
|
|
{
|
2016-05-31 11:18:01 +00:00
|
|
|
return tbf ? tbf->name() : "(no TBF)";
|
2015-03-03 13:45:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *gprs_rlcmac_tbf::name() const
|
|
|
|
{
|
|
|
|
snprintf(m_name_buf, sizeof(m_name_buf) - 1,
|
2015-11-27 15:17:40 +00:00
|
|
|
"TBF(TFI=%d TLLI=0x%08x DIR=%s STATE=%s%s)",
|
2015-05-20 10:06:46 +00:00
|
|
|
m_tfi, tlli(),
|
2015-03-03 13:45:55 +00:00
|
|
|
direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
|
2015-11-27 15:17:40 +00:00
|
|
|
state_name(),
|
|
|
|
is_egprs_enabled() ? " EGPRS" : ""
|
2015-03-03 13:45:55 +00:00
|
|
|
);
|
|
|
|
m_name_buf[sizeof(m_name_buf) - 1] = '\0';
|
|
|
|
return m_name_buf;
|
2013-10-27 15:39:36 +00:00
|
|
|
}
|
2013-11-06 19:39:45 +00:00
|
|
|
|
2013-11-26 12:08:12 +00:00
|
|
|
void gprs_rlcmac_tbf::rotate_in_list()
|
|
|
|
{
|
2021-01-14 15:48:38 +00:00
|
|
|
llist_del(tbf_bts_list((struct gprs_rlcmac_tbf *)this));
|
2013-11-26 12:08:12 +00:00
|
|
|
if (direction == GPRS_RLCMAC_UL_TBF)
|
2021-01-14 15:48:38 +00:00
|
|
|
llist_add(tbf_bts_list((struct gprs_rlcmac_tbf *)this), &bts->ul_tbfs);
|
2013-11-26 12:08:12 +00:00
|
|
|
else
|
2021-01-14 15:48:38 +00:00
|
|
|
llist_add(tbf_bts_list((struct gprs_rlcmac_tbf *)this), &bts->dl_tbfs);
|
2013-11-26 12:08:12 +00:00
|
|
|
}
|
2013-12-25 19:22:35 +00:00
|
|
|
|
|
|
|
uint8_t gprs_rlcmac_tbf::tsc() const
|
|
|
|
{
|
|
|
|
return trx->pdch[first_ts].tsc;
|
|
|
|
}
|
2014-01-15 16:06:19 +00:00
|
|
|
|
2015-06-30 07:18:30 +00:00
|
|
|
uint8_t gprs_rlcmac_tbf::dl_slots() const
|
|
|
|
{
|
|
|
|
uint8_t slots = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (direction == GPRS_RLCMAC_UL_TBF)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pdch); i += 1)
|
|
|
|
if (pdch[i])
|
|
|
|
slots |= 1 << i;
|
|
|
|
|
|
|
|
return slots;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t gprs_rlcmac_tbf::ul_slots() const
|
|
|
|
{
|
|
|
|
uint8_t slots = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (direction == GPRS_RLCMAC_DL_TBF) {
|
|
|
|
if (control_ts < 8)
|
|
|
|
slots |= 1 << control_ts;
|
|
|
|
if (first_common_ts < 8)
|
|
|
|
slots |= 1 << first_common_ts;
|
|
|
|
|
|
|
|
return slots;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pdch); i += 1)
|
|
|
|
if (pdch[i])
|
|
|
|
slots |= 1 << i;
|
|
|
|
|
|
|
|
return slots;
|
|
|
|
}
|
2016-01-22 16:41:33 +00:00
|
|
|
|
|
|
|
bool gprs_rlcmac_tbf::is_control_ts(uint8_t ts) const
|
|
|
|
{
|
|
|
|
return ts == control_ts;
|
|
|
|
}
|
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
|
|
|
|
|
|
|
/* C API */
|
|
|
|
enum gprs_rlcmac_tbf_state tbf_state(const struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return tbf->state;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum gprs_rlcmac_tbf_direction tbf_direction(const struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return tbf->direction;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tbf_set_ms(struct gprs_rlcmac_tbf *tbf, GprsMs *ms)
|
|
|
|
{
|
|
|
|
tbf->set_ms(ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct llist_head *tbf_ms_list(struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return &tbf->m_ms_list.list;
|
|
|
|
}
|
|
|
|
|
2021-01-14 15:48:38 +00:00
|
|
|
struct llist_head *tbf_bts_list(struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return &tbf->m_bts_list.list;
|
|
|
|
}
|
|
|
|
|
2021-01-27 12:22:03 +00:00
|
|
|
struct GprsMs *tbf_ms(const struct gprs_rlcmac_tbf *tbf)
|
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 tbf->ms();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tbf_timers_pending(struct gprs_rlcmac_tbf *tbf, enum tbf_timers t)
|
|
|
|
{
|
|
|
|
return tbf->timers_pending(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct gprs_llc *tbf_llc(struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return &tbf->m_llc;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t tbf_first_common_ts(const struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return tbf->first_common_ts;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t tbf_dl_slots(const struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return tbf->dl_slots();
|
|
|
|
}
|
|
|
|
uint8_t tbf_ul_slots(const struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return tbf->ul_slots();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tbf_is_tfi_assigned(const struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return tbf->is_tfi_assigned();
|
|
|
|
}
|
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
|
|
|
|
|
|
|
uint8_t tbf_tfi(const struct gprs_rlcmac_tbf *tbf)
|
|
|
|
{
|
|
|
|
return tbf->tfi();
|
|
|
|
}
|
2021-02-01 13:52:48 +00:00
|
|
|
|
|
|
|
int tbf_check_polling(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts, uint32_t *poll_fn, unsigned int *rrbp)
|
|
|
|
{
|
|
|
|
return tbf->check_polling(fn, ts, poll_fn, rrbp);
|
|
|
|
}
|
|
|
|
|
2021-03-29 16:15:30 +00:00
|
|
|
void tbf_set_polling(struct gprs_rlcmac_tbf *tbf, uint32_t new_poll_fn, uint8_t ts, enum pdch_ulc_tbf_poll_reason t)
|
2021-02-01 13:52:48 +00:00
|
|
|
{
|
|
|
|
return tbf->set_polling(new_poll_fn, ts, t);
|
|
|
|
}
|
2021-03-09 16:18:12 +00:00
|
|
|
|
2021-03-29 16:15:30 +00:00
|
|
|
void tbf_poll_timeout(struct gprs_rlcmac_tbf *tbf, enum pdch_ulc_tbf_poll_reason reason)
|
2021-03-09 16:18:12 +00:00
|
|
|
{
|
2021-03-29 16:15:30 +00:00
|
|
|
tbf->poll_timeout(reason);
|
2021-03-09 16:18:12 +00:00
|
|
|
}
|