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