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
This commit is contained in:
Pau Espin Pedrol 2020-12-16 15:59:45 +01:00 committed by pespin
parent 86fad1ec4e
commit da971ee502
32 changed files with 1977 additions and 1920 deletions

View File

@ -47,7 +47,7 @@ libgprs_la_SOURCES = \
gprs_rlcmac_sched.cpp \
gprs_rlcmac_meas.cpp \
gprs_rlcmac_ts_alloc.cpp \
gprs_ms.cpp \
gprs_ms.c \
gprs_ms_storage.cpp \
gsm_timer.cpp \
pcu_l1_if.cpp \

View File

@ -712,7 +712,7 @@ int BTS::rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn)
ms = ms_by_tlli(tlli);
if (ms)
dl_tbf = ms->dl_tbf();
dl_tbf = ms_dl_tbf(ms);
if (!dl_tbf) {
LOGP(DRLCMAC, LOGL_ERROR, "Got IMM.ASS confirm, but TLLI=%08x "
"does not exit\n", tlli);
@ -1140,9 +1140,9 @@ GprsMs *BTS::ms_alloc(uint8_t ms_class, uint8_t egprs_ms_class)
GprsMs *ms;
ms = ms_store().create_ms();
ms->set_timeout(osmo_tdef_get(m_bts.T_defs_pcu, -2030, OSMO_TDEF_S, -1));
ms->set_ms_class(ms_class);
ms->set_egprs_ms_class(egprs_ms_class);
ms_set_timeout(ms, osmo_tdef_get(m_bts.T_defs_pcu, -2030, OSMO_TDEF_S, -1));
ms_set_ms_class(ms, ms_class);
ms_set_egprs_ms_class(ms, egprs_ms_class);
return ms;
}
@ -1206,22 +1206,22 @@ void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, i
}
}
void gprs_rlcmac_trx::reserve_slots(enum gprs_rlcmac_tbf_direction dir,
void bts_trx_reserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir,
uint8_t slots)
{
unsigned i;
for (i = 0; i < ARRAY_SIZE(pdch); i += 1)
for (i = 0; i < ARRAY_SIZE(trx->pdch); i += 1)
if (slots & (1 << i))
pdch[i].reserve(dir);
trx->pdch[i].reserve(dir);
}
void gprs_rlcmac_trx::unreserve_slots(enum gprs_rlcmac_tbf_direction dir,
void bts_trx_unreserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir,
uint8_t slots)
{
unsigned i;
for (i = 0; i < ARRAY_SIZE(pdch); i += 1)
for (i = 0; i < ARRAY_SIZE(trx->pdch); i += 1)
if (slots & (1 << i))
pdch[i].unreserve(dir);
trx->pdch[i].unreserve(dir);
}
void bts_set_max_cs(struct gprs_rlcmac_bts *bts, uint8_t cs_dl, uint8_t cs_ul)
@ -1277,3 +1277,34 @@ void bts_set_max_mcs(struct gprs_rlcmac_bts *bts, uint8_t mcs_dl, uint8_t mcs_ul
bts->bts->set_max_mcs_dl(mcs_dl);
bts->bts->set_max_mcs_ul(mcs_ul);
}
struct gprs_rlcmac_bts *bts_data(struct BTS *bts)
{
return &bts->m_bts;
}
struct GprsMs *bts_ms_by_imsi(struct BTS *bts, const char *imsi)
{
return bts->ms_by_imsi(imsi);
}
uint8_t bts_max_cs_dl(const struct BTS *bts)
{
return bts->max_cs_dl();
}
uint8_t bts_max_cs_ul(const struct BTS *bts)
{
return bts->max_cs_ul();
}
uint8_t bts_max_mcs_dl(const struct BTS *bts)
{
return bts->max_mcs_dl();
}
uint8_t bts_max_mcs_ul(const struct BTS *bts)
{
return bts->max_mcs_ul();
}

View File

@ -90,15 +90,14 @@ struct gprs_rlcmac_trx {
struct BTS *bts;
uint8_t trx_no;
#ifdef __cplusplus
void reserve_slots(enum gprs_rlcmac_tbf_direction dir, uint8_t slots);
void unreserve_slots(enum gprs_rlcmac_tbf_direction dir, uint8_t slots);
#endif
};
#ifdef __cplusplus
extern "C" {
#endif
void bts_trx_reserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir, uint8_t slots);
void bts_trx_unreserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir, uint8_t slots);
void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, int8_t ta, bool is_rach);
#ifdef __cplusplus
}
@ -372,10 +371,11 @@ public:
LListHead<gprs_rlcmac_tbf>& ul_tbfs();
LListHead<gprs_rlcmac_tbf>& dl_tbfs();
struct gprs_rlcmac_bts m_bts;
private:
int m_cur_fn;
int m_cur_blk_fn;
struct gprs_rlcmac_bts m_bts;
uint8_t m_max_cs_dl, m_max_cs_ul;
uint8_t m_max_mcs_dl, m_max_mcs_ul;
PollController m_pollController;
@ -459,11 +459,17 @@ inline void BTS::stat_item_add(unsigned int stat_id, int inc) {
extern "C" {
#endif
void bts_cleanup();
struct gprs_rlcmac_bts *bts_data(struct BTS *bts);
struct gprs_rlcmac_bts *bts_main_data();
struct rate_ctr_group *bts_main_data_stats();
struct osmo_stat_item_group *bts_main_data_stat_items();
void bts_set_max_cs(struct gprs_rlcmac_bts *bts, uint8_t cs_dl, uint8_t cs_ul);
void bts_set_max_mcs(struct gprs_rlcmac_bts *bts, uint8_t mcs_dl, uint8_t mcs_ul);
struct GprsMs *bts_ms_by_imsi(struct BTS *bts, const char *imsi);
uint8_t bts_max_cs_dl(const struct BTS *bts);
uint8_t bts_max_cs_ul(const struct BTS *bts);
uint8_t bts_max_mcs_dl(const struct BTS *bts);
uint8_t bts_max_mcs_ul(const struct BTS *bts);
#ifdef __cplusplus
}

View File

@ -1388,7 +1388,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_gprs(
delimiter = data_block + *num_chunks;
e_pointer = (*num_chunks ? delimiter - 1 : NULL);
chunk = llc->chunk_size();
chunk = llc_chunk_size(llc);
space = rdbi->data_len - *offset;
/* if chunk will exceed block limit */
@ -1402,7 +1402,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_gprs(
*e_pointer |= 0x02; /* set previous M bit = 1 */
}
/* fill only space */
llc->consume(data, space);
llc_consume_data(llc, data, space);
if (count_payload)
*count_payload = space;
/* return data block as message */
@ -1421,7 +1421,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_gprs(
if (e_pointer)
*e_pointer |= 0x01;
/* fill space */
llc->consume(data, space);
llc_consume_data(llc, data, space);
if (count_payload)
*count_payload = space;
*offset = rdbi->data_len;
@ -1454,7 +1454,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_gprs(
rdbi->e = 0; /* 0: extensions present */
// no need to set e_pointer nor increase delimiter
/* fill only space, which is 1 octet less than chunk */
llc->consume(data, space);
llc_consume_data(llc, data, space);
if (count_payload)
*count_payload = space;
/* return data block as message */
@ -1485,7 +1485,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_gprs(
rdbi->e = 0; /* 0: extensions present */
(*num_chunks)++;
/* copy (rest of) LLC frame to space and reset later */
llc->consume(data, chunk);
llc_consume_data(llc, data, chunk);
if (count_payload)
*count_payload = chunk;
data += chunk;
@ -1536,7 +1536,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_egprs(
prev_li = (struct rlc_li_field_egprs *)
(*num_chunks ? delimiter - 1 : NULL);
chunk = llc->chunk_size();
chunk = llc_chunk_size(llc);
space = rdbi->data_len - *offset;
/* if chunk will exceed block limit */
@ -1546,7 +1546,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_egprs(
"only remaining space, and we are done\n",
chunk, space);
/* fill only space */
llc->consume(data, space);
llc_consume_data(llc, data, space);
if (count_payload)
*count_payload = space;
/* return data block as message */
@ -1562,7 +1562,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_egprs(
"this is a final block, we don't add length "
"header, and we are done\n", chunk, space);
/* fill space */
llc->consume(data, space);
llc_consume_data(llc, data, space);
if (count_payload)
*count_payload = space;
*offset = rdbi->data_len;
@ -1578,7 +1578,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_egprs(
"to start with an empty chunk\n",
chunk, space);
/* fill space */
llc->consume(data, space);
llc_consume_data(llc, data, space);
if (count_payload)
*count_payload = space;
*offset = rdbi->data_len;
@ -1610,7 +1610,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_egprs(
prev_li = li;
(*num_chunks)++;
/* copy (rest of) LLC frame to space and reset later */
llc->consume(data, chunk);
llc_consume_data(llc, data, chunk);
if (count_payload)
*count_payload = chunk;
data += chunk;

885
src/gprs_ms.c Normal file
View File

@ -0,0 +1,885 @@
/* gprs_ms.c
*
* Copyright (C) 2015-2020 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gprs_ms.h"
#include "bts.h"
#include "tbf.h"
#include "tbf_ul.h"
#include "gprs_debug.h"
#include "gprs_codel.h"
#include "pcu_utils.h"
#include <time.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/core/logging.h>
#include "coding_scheme.h"
#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
extern void *tall_pcu_ctx;
static int64_t now_msec()
{
struct timespec ts;
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
return (int64_t)(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
}
void gprs_default_cb_ms_idle(struct GprsMs *ms)
{
talloc_free(ms);
}
void gprs_default_cb_ms_active(struct GprsMs *ms)
{
/* do nothing */
}
static struct gpr_ms_callback gprs_default_cb = {
.ms_idle = gprs_default_cb_ms_idle,
.ms_active = gprs_default_cb_ms_active,
};
void ms_timeout(void *data)
{
struct GprsMs *ms = (struct GprsMs *) data;
LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",
ms_tlli(ms));
if (ms->timer.data) {
ms->timer.data = NULL;
ms_unref(ms);
}
}
static int ms_talloc_destructor(struct GprsMs *ms);
struct GprsMs *ms_alloc(struct BTS *bts, uint32_t tlli)
{
struct GprsMs *ms = talloc_zero(tall_pcu_ctx, struct GprsMs);
talloc_set_destructor(ms, ms_talloc_destructor);
ms->bts = bts;
ms->cb = gprs_default_cb;
ms->tlli = tlli;
ms->new_ul_tlli = GSM_RESERVED_TMSI;
ms->new_dl_tlli = GSM_RESERVED_TMSI;
ms->ta = GSM48_TA_INVALID;
ms->current_cs_ul = UNKNOWN;
ms->current_cs_dl = UNKNOWN;
ms->is_idle = true;
INIT_LLIST_HEAD(&ms->list);
INIT_LLIST_HEAD(&ms->old_tbfs);
int codel_interval = LLC_CODEL_USE_DEFAULT;
LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
ms->imsi[0] = '\0';
memset(&ms->timer, 0, sizeof(ms->timer));
ms->timer.cb = ms_timeout;
llc_queue_init(&ms->llc_queue);
ms_set_mode(ms, GPRS);
if (ms->bts)
codel_interval = bts_data(ms->bts)->llc_codel_interval_msec;
if (codel_interval) {
if (codel_interval == LLC_CODEL_USE_DEFAULT)
codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;
ms->codel_state = talloc(ms, struct gprs_codel);
gprs_codel_init(ms->codel_state);
gprs_codel_set_interval(ms->codel_state, codel_interval);
}
ms->last_cs_not_low = now_msec();
ms->app_info_pending = false;
return ms;
}
static int ms_talloc_destructor(struct GprsMs *ms)
{
struct llist_item *pos, *tmp;
LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", ms_tlli(ms));
ms_set_reserved_slots(ms, NULL, 0, 0);
if (osmo_timer_pending(&ms->timer))
osmo_timer_del(&ms->timer);
if (ms->ul_tbf) {
tbf_set_ms((struct gprs_rlcmac_tbf *)ms->ul_tbf, NULL);
ms->ul_tbf = NULL;
}
if (ms->dl_tbf) {
tbf_set_ms((struct gprs_rlcmac_tbf *)ms->dl_tbf, NULL);
ms->dl_tbf = NULL;
}
llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {
struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)pos->entry;
tbf_set_ms(tbf, NULL);
}
llc_queue_clear(&ms->llc_queue, ms->bts);
return 0;
}
void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb)
{
if (cb)
ms->cb = *cb;
else
ms->cb = gprs_default_cb;
}
static void ms_update_status(struct GprsMs *ms)
{
if (ms->ref > 0)
return;
if (ms_is_idle(ms) && !ms->is_idle) {
ms->is_idle = true;
ms->cb.ms_idle(ms);
/* this can be deleted by now, do not access it */
return;
}
if (!ms_is_idle(ms) && ms->is_idle) {
ms->is_idle = false;
ms->cb.ms_active(ms);
}
}
struct GprsMs *ms_ref(struct GprsMs *ms)
{
ms->ref += 1;
return ms;
}
void ms_unref(struct GprsMs *ms)
{
OSMO_ASSERT(ms->ref >= 0);
ms->ref -= 1;
if (ms->ref == 0)
ms_update_status(ms);
}
void ms_start_timer(struct GprsMs *ms)
{
if (ms->delay == 0)
return;
if (!ms->timer.data)
ms->timer.data = ms_ref(ms);
osmo_timer_schedule(&ms->timer, ms->delay, 0);
}
void ms_stop_timer(struct GprsMs *ms)
{
if (!ms->timer.data)
return;
osmo_timer_del(&ms->timer);
ms->timer.data = NULL;
ms_unref(ms);
}
void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode)
{
ms->mode = mode;
if (!ms->bts)
return;
switch (ms->mode) {
case GPRS:
if (!mcs_is_gprs(ms->current_cs_ul)) {
ms->current_cs_ul = mcs_get_gprs_by_num(
bts_data(ms->bts)->initial_cs_ul);
if (!mcs_is_valid(ms->current_cs_ul))
ms->current_cs_ul = CS1;
}
if (!mcs_is_gprs(ms->current_cs_dl)) {
ms->current_cs_dl = mcs_get_gprs_by_num(
bts_data(ms->bts)->initial_cs_dl);
if (!mcs_is_valid(ms->current_cs_dl))
ms->current_cs_dl = CS1;
}
break;
case EGPRS_GMSK:
case EGPRS:
if (!mcs_is_edge(ms->current_cs_ul)) {
ms->current_cs_ul = mcs_get_egprs_by_num(
bts_data(ms->bts)->initial_mcs_ul);
if (!mcs_is_valid(ms->current_cs_ul))
ms->current_cs_ul = MCS1;
}
if (!mcs_is_edge(ms->current_cs_dl)) {
ms->current_cs_dl = mcs_get_egprs_by_num(
bts_data(ms->bts)->initial_mcs_dl);
if (!mcs_is_valid(ms->current_cs_dl))
ms->current_cs_dl = MCS1;
}
break;
}
}
static void ms_attach_ul_tbf(struct GprsMs *ms, struct gprs_rlcmac_ul_tbf *tbf)
{
if (ms->ul_tbf == tbf)
return;
LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
ms_tlli(ms), tbf_name((struct gprs_rlcmac_tbf *)tbf));
ms_ref(ms);
if (ms->ul_tbf)
llist_add_tail(tbf_ms_list((struct gprs_rlcmac_tbf *)ms->ul_tbf), &ms->old_tbfs);
ms->ul_tbf = tbf;
if (tbf)
ms_stop_timer(ms);
ms_unref(ms);
}
static void ms_attach_dl_tbf(struct GprsMs *ms, struct gprs_rlcmac_dl_tbf *tbf)
{
if (ms->dl_tbf == tbf)
return;
LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
ms_tlli(ms), tbf_name((struct gprs_rlcmac_tbf *)tbf));
ms_ref(ms);
if (ms->dl_tbf)
llist_add_tail(tbf_ms_list((struct gprs_rlcmac_tbf *)ms->dl_tbf), &ms->old_tbfs);
ms->dl_tbf = tbf;
if (tbf)
ms_stop_timer(ms);
ms_unref(ms);
}
void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
{
if (tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF)
ms_attach_dl_tbf(ms, as_dl_tbf(tbf));
else
ms_attach_ul_tbf(ms, as_ul_tbf(tbf));
}
void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
{
if (tbf == (struct gprs_rlcmac_tbf *)(ms->ul_tbf)) {
ms->ul_tbf = NULL;
} else if (tbf == (struct gprs_rlcmac_tbf *)(ms->dl_tbf)) {
ms->dl_tbf = NULL;
} else {
bool found = false;
struct llist_item *pos, *tmp;
llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {
struct gprs_rlcmac_tbf *tmp_tbf = (struct gprs_rlcmac_tbf *)pos->entry;
if (tmp_tbf == tbf) {
llist_del(&pos->list);
found = true;
break;
}
}
/* Protect against recursive calls via set_ms() */
if (!found)
return;
}
LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",
ms_tlli(ms), tbf_name(tbf));
if (tbf_ms(tbf) == ms)
tbf_set_ms(tbf, NULL);
if (!ms->dl_tbf && !ms->ul_tbf) {
ms_set_reserved_slots(ms, NULL, 0, 0);
if (ms_tlli(ms) != 0)
ms_start_timer(ms);
}
ms_update_status(ms);
}
void ms_reset(struct GprsMs *ms)
{
LOGP(DRLCMAC, LOGL_INFO,
"Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",
ms_tlli(ms), ms_imsi(ms));
ms_stop_timer(ms);
ms->tlli = GSM_RESERVED_TMSI;
ms->new_dl_tlli = ms->tlli;
ms->new_ul_tlli = ms->tlli;
ms->imsi[0] = '\0';
}
static void ms_merge_old_ms(struct GprsMs *ms, struct GprsMs *old_ms)
{
OSMO_ASSERT(old_ms != ms);
if (strlen(ms_imsi(ms)) == 0 && strlen(ms_imsi(old_ms)) != 0)
osmo_strlcpy(ms->imsi, ms_imsi(old_ms), sizeof(ms->imsi));
if (!ms_ms_class(ms) && ms_ms_class(old_ms))
ms_set_ms_class(ms, ms_ms_class(old_ms));
if (!ms_egprs_ms_class(ms) && ms_egprs_ms_class(old_ms))
ms_set_egprs_ms_class(ms, ms_egprs_ms_class(old_ms));
llc_queue_move_and_merge(&ms->llc_queue, &old_ms->llc_queue);
ms_reset(old_ms);
}
void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms)
{
OSMO_ASSERT(old_ms != ms);
ms_ref(old_ms);
/* Clean up the old MS object */
/* TODO: Use timer? */
if (ms_ul_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms), T_MAX))
tbf_free((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms));
if (ms_dl_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms), T_MAX))
tbf_free((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms));
ms_merge_old_ms(ms, old_ms);
ms_unref(old_ms);
}
void ms_set_tlli(struct GprsMs *ms, uint32_t tlli)
{
if (tlli == ms->tlli || tlli == ms->new_ul_tlli)
return;
if (tlli != ms->new_dl_tlli) {
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
"not yet confirmed\n",
ms_tlli(ms), tlli);
ms->new_ul_tlli = tlli;
return;
}
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
"already confirmed partly\n",
ms->tlli, tlli);
ms->tlli = tlli;
ms->new_dl_tlli = GSM_RESERVED_TMSI;
ms->new_ul_tlli = GSM_RESERVED_TMSI;
}
bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli)
{
if (tlli == ms->tlli || tlli == ms->new_dl_tlli)
return false;
if (tlli != ms->new_ul_tlli) {
/* The MS has not sent a message with the new TLLI, which may
* happen according to the spec [TODO: add reference]. */
LOGP(DRLCMAC, LOGL_INFO,
"The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
"partly confirmed\n", tlli);
/* Use the network's idea of TLLI as candidate, this does not
* change the result value of tlli() */
ms->new_dl_tlli = tlli;
return false;
}
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
ms->tlli = tlli;
ms->new_dl_tlli = GSM_RESERVED_TMSI;
ms->new_ul_tlli = GSM_RESERVED_TMSI;
return true;
}
void ms_set_imsi(struct GprsMs *ms, const char *imsi)
{
if (!imsi) {
LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
return;
}
if (imsi[0] && strlen(imsi) < 3) {
LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
imsi);
return;
}
if (strcmp(imsi, ms->imsi) == 0)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
ms_tlli(ms), ms->imsi, imsi);
struct GprsMs *old_ms = bts_ms_by_imsi(ms->bts, imsi);
/* Check if we are going to store a different MS object with already
existing IMSI. This is probably a bug in code calling this function,
since it should take care of this explicitly */
if (old_ms) {
/* We cannot find ms->ms by IMSI since we know that it has a
* different IMSI */
OSMO_ASSERT(old_ms != ms);
LOGPMS(ms, DRLCMAC, LOGL_NOTICE,
"IMSI '%s' was already assigned to another "
"MS object: TLLI = 0x%08x, that IMSI will be removed\n",
imsi, ms_tlli(old_ms));
ms_merge_and_clear_ms(ms, old_ms);
}
osmo_strlcpy(ms->imsi, imsi, sizeof(ms->imsi));
}
void ms_set_ta(struct GprsMs *ms, uint8_t ta_)
{
if (ta_ == ms->ta)
return;
if (gsm48_ta_is_valid(ta_)) {
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
ms_tlli(ms), ms->ta, ta_);
ms->ta = ta_;
} else
LOGP(DRLCMAC, LOGL_NOTICE,
"MS object, TLLI = 0x%08x, invalid TA %d rejected (old "
"value %d kept)\n", ms_tlli(ms), ta_, ms->ta);
}
void ms_set_ms_class(struct GprsMs *ms, uint8_t ms_class_)
{
if (ms_class_ == ms->ms_class)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
ms_tlli(ms), ms->ms_class, ms_class_);
ms->ms_class = ms_class_;
}
void ms_set_egprs_ms_class(struct GprsMs *ms, uint8_t ms_class_)
{
if (ms_class_ == ms->egprs_ms_class)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",
ms_tlli(ms), ms->egprs_ms_class, ms_class_);
ms->egprs_ms_class = ms_class_;
if (!bts_max_mcs_ul(ms->bts) || !bts_max_mcs_dl(ms->bts)) {
LOGPMS(ms, DRLCMAC, LOGL_DEBUG,
"Avoid enabling EGPRS because use of MCS is disabled: ul=%u dl=%u\n",
bts_max_mcs_ul(ms->bts), bts_max_mcs_dl(ms->bts));
return;
}
if (mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts))) &&
mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts))) &&
ms_mode(ms) != EGPRS)
{
ms_set_mode(ms, EGPRS_GMSK);
} else {
ms_set_mode(ms, EGPRS);
}
LOGPMS(ms, DRLCMAC, LOGL_INFO, "Enabled EGPRS, mode %s\n", mode_name(ms_mode(ms)));
}
void ms_update_error_rate(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, int error_rate)
{
struct gprs_rlcmac_bts *bts_;
int64_t now;
enum CodingScheme max_cs_dl = ms_max_cs_dl(ms);
OSMO_ASSERT(max_cs_dl);
bts_ = bts_data(ms->bts);
if (error_rate < 0)
return;
now = now_msec();
/* TODO: Check for TBF direction */
/* TODO: Support different CS values for UL and DL */
ms->nack_rate_dl = error_rate;
if (error_rate > bts_->cs_adj_upper_limit) {
if (mcs_chan_code(ms->current_cs_dl) > 0) {
mcs_dec_kind(&ms->current_cs_dl, ms_mode(ms));
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): High error rate %d%%, "
"reducing CS level to %s\n",
ms_imsi(ms), error_rate, mcs_name(ms->current_cs_dl));
ms->last_cs_not_low = now;
}
} else if (error_rate < bts_->cs_adj_lower_limit) {
if (ms->current_cs_dl < max_cs_dl) {
if (now - ms->last_cs_not_low > 1000) {
mcs_inc_kind(&ms->current_cs_dl, ms_mode(ms));
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): Low error rate %d%%, "
"increasing DL CS level to %s\n",
ms_imsi(ms), error_rate,
mcs_name(ms->current_cs_dl));
ms->last_cs_not_low = now;
} else {
LOGP(DRLCMACDL, LOGL_DEBUG,
"MS (IMSI %s): Low error rate %d%%, "
"ignored (within blocking period)\n",
ms_imsi(ms), error_rate);
}
}
} else {
LOGP(DRLCMACDL, LOGL_DEBUG,
"MS (IMSI %s): Medium error rate %d%%, ignored\n",
ms_imsi(ms), error_rate);
ms->last_cs_not_low = now;
}
}
enum CodingScheme ms_max_cs_ul(const struct GprsMs *ms)
{
OSMO_ASSERT(ms->bts != NULL);
if (mcs_is_gprs(ms->current_cs_ul)) {
if (!bts_max_cs_ul(ms->bts)) {
return CS4;
}
return mcs_get_gprs_by_num(bts_max_cs_ul(ms->bts));
}
if (!mcs_is_edge(ms->current_cs_ul))
return UNKNOWN;
if (bts_max_mcs_ul(ms->bts))
return mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts));
else if (bts_max_cs_ul(ms->bts))
return mcs_get_gprs_by_num(bts_max_cs_ul(ms->bts));
return MCS4;
}
void ms_set_current_cs_dl(struct GprsMs *ms, enum CodingScheme scheme)
{
ms->current_cs_dl = scheme;
}
enum CodingScheme ms_max_cs_dl(const struct GprsMs *ms)
{
OSMO_ASSERT(ms->bts != NULL);
if (mcs_is_gprs(ms->current_cs_dl)) {
if (!bts_max_cs_dl(ms->bts)) {
return CS4;
}
return mcs_get_gprs_by_num(bts_max_cs_dl(ms->bts));
}
if (!mcs_is_edge(ms->current_cs_dl))
return UNKNOWN;
if (bts_max_mcs_dl(ms->bts))
return mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts));
else if (bts_max_cs_dl(ms->bts))
return mcs_get_gprs_by_num(bts_max_cs_dl(ms->bts));
return MCS4;
}
void ms_update_cs_ul(struct GprsMs *ms, const struct pcu_l1_meas *meas)
{
struct gprs_rlcmac_bts *bts_;
enum CodingScheme max_cs_ul = ms_max_cs_ul(ms);
int old_link_qual;
int low;
int high;
enum CodingScheme new_cs_ul = ms->current_cs_ul;
uint8_t current_cs = mcs_chan_code(ms->current_cs_ul);
bts_ = bts_data(ms->bts);
if (!max_cs_ul) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"max_cs_ul cannot be derived (current UL CS: %s)\n",
mcs_name(ms->current_cs_ul));
return;
}
if (!ms->current_cs_ul) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS because it's not set: %s\n",
mcs_name(ms->current_cs_ul));
return;
}
if (!meas->have_link_qual) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS %s because we don't have link quality measurements.\n",
mcs_name(ms->current_cs_ul));
return;
}
if (mcs_is_gprs(ms->current_cs_ul)) {
if (current_cs >= MAX_GPRS_CS)
current_cs = MAX_GPRS_CS - 1;
low = bts_->cs_lqual_ranges[current_cs].low;
high = bts_->cs_lqual_ranges[current_cs].high;
} else if (mcs_is_edge(ms->current_cs_ul)) {
if (current_cs >= MAX_EDGE_MCS)
current_cs = MAX_EDGE_MCS - 1;
low = bts_->mcs_lqual_ranges[current_cs].low;
high = bts_->mcs_lqual_ranges[current_cs].high;
} else {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",
mcs_name(ms->current_cs_ul));
return;
}
/* To avoid rapid changes of the coding scheme, we also take
* the old link quality value into account (if present). */
if (ms->l1_meas.have_link_qual)
old_link_qual = ms->l1_meas.link_qual;
else
old_link_qual = meas->link_qual;
if (meas->link_qual < low && old_link_qual < low)
mcs_dec_kind(&new_cs_ul, ms_mode(ms));
else if (meas->link_qual > high && old_link_qual > high &&
ms->current_cs_ul < max_cs_ul)
mcs_inc_kind(&new_cs_ul, ms_mode(ms));
if (ms->current_cs_ul != new_cs_ul) {
LOGPMS(ms, DRLCMACMEAS, LOGL_INFO,
"Link quality %ddB (old %ddB) left window [%d, %d], "
"modifying uplink CS level: %s -> %s\n",
meas->link_qual, old_link_qual,
low, high,
mcs_name(ms->current_cs_ul), mcs_name(new_cs_ul));
ms->current_cs_ul = new_cs_ul;
}
}
void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas)
{
unsigned i;
ms_update_cs_ul(ms, meas);
if (meas->have_rssi)
pcu_l1_meas_set_rssi(&ms->l1_meas, meas->rssi);
if (meas->have_bto)
pcu_l1_meas_set_bto(&ms->l1_meas, meas->bto);
if (meas->have_ber)
pcu_l1_meas_set_ber(&ms->l1_meas, meas->ber);
if (meas->have_link_qual)
pcu_l1_meas_set_link_qual(&ms->l1_meas, meas->link_qual);
if (meas->have_ms_rx_qual)
pcu_l1_meas_set_ms_rx_qual(&ms->l1_meas, meas->ms_rx_qual);
if (meas->have_ms_c_value)
pcu_l1_meas_set_ms_c_value(&ms->l1_meas, meas->ms_c_value);
if (meas->have_ms_sign_var)
pcu_l1_meas_set_ms_sign_var(&ms->l1_meas, meas->ms_sign_var);
if (meas->have_ms_i_level) {
for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
if (meas->ts[i].have_ms_i_level)
pcu_l1_meas_set_ms_i_level(&ms->l1_meas, i, meas->ts[i].ms_i_level);
else
ms->l1_meas.ts[i].have_ms_i_level = 0;
}
}
}
enum CodingScheme ms_current_cs_dl(const struct GprsMs *ms)
{
enum CodingScheme cs = ms->current_cs_dl;
size_t unencoded_octets;
if (!ms->bts)
return cs;
unencoded_octets = llc_queue_octets(&ms->llc_queue);
/* If the DL TBF is active, add number of unencoded chunk octets */
if (ms->dl_tbf)
unencoded_octets += llc_chunk_size(tbf_llc((struct gprs_rlcmac_tbf *)ms->dl_tbf));
/* There are many unencoded octets, don't reduce */
if (unencoded_octets >= bts_data(ms->bts)->cs_downgrade_threshold)
return cs;
/* RF conditions are good, don't reduce */
if (ms->nack_rate_dl < bts_data(ms->bts)->cs_adj_lower_limit)
return cs;
/* The throughput would probably be better if the CS level was reduced */
mcs_dec_kind(&cs, ms_mode(ms));
/* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
if (cs == CS2)
mcs_dec_kind(&cs, ms_mode(ms));
return cs;
}
int ms_first_common_ts(const struct GprsMs *ms)
{
if (ms->dl_tbf)
return tbf_first_common_ts((struct gprs_rlcmac_tbf *)ms->dl_tbf);
if (ms->ul_tbf)
return tbf_first_common_ts((struct gprs_rlcmac_tbf *)ms->ul_tbf);
return -1;
}
uint8_t ms_dl_slots(const struct GprsMs *ms)
{
uint8_t slots = 0;
if (ms->dl_tbf)
slots |= tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
if (ms->ul_tbf)
slots |= tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
return slots;
}
uint8_t ms_ul_slots(const struct GprsMs *ms)
{
uint8_t slots = 0;
if (ms->dl_tbf)
slots |= tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
if (ms->ul_tbf)
slots |= tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
return slots;
}
uint8_t ms_current_pacch_slots(const struct GprsMs *ms)
{
uint8_t slots = 0;
bool is_dl_active = ms->dl_tbf && tbf_is_tfi_assigned((struct gprs_rlcmac_tbf *)ms->dl_tbf);
bool is_ul_active = ms->ul_tbf && tbf_is_tfi_assigned((struct gprs_rlcmac_tbf *)ms->ul_tbf);
if (!is_dl_active && !is_ul_active)
return 0;
/* see TS 44.060, 8.1.1.2.2 */
if (is_dl_active && !is_ul_active)
slots = tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
else if (!is_dl_active && is_ul_active)
slots = tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
else
slots = tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf) &
tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
/* Assume a multislot class 1 device */
/* TODO: For class 2 devices, this could be removed */
slots = pcu_lsb(slots);
return slots;
}
void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,
uint8_t ul_slots, uint8_t dl_slots)
{
if (ms->current_trx) {
bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,
ms->reserved_dl_slots);
bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,
ms->reserved_ul_slots);
ms->reserved_dl_slots = 0;
ms->reserved_ul_slots = 0;
}
ms->current_trx = trx;
if (trx) {
ms->reserved_dl_slots = dl_slots;
ms->reserved_ul_slots = ul_slots;
bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,
ms->reserved_dl_slots);
bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,
ms->reserved_ul_slots);
}
}
struct gprs_rlcmac_tbf *ms_tbf(const struct GprsMs *ms, enum gprs_rlcmac_tbf_direction dir)
{
switch (dir) {
case GPRS_RLCMAC_DL_TBF: return (struct gprs_rlcmac_tbf *)ms->dl_tbf;
case GPRS_RLCMAC_UL_TBF: return (struct gprs_rlcmac_tbf *)ms->ul_tbf;
}
return NULL;
}

View File

@ -1,900 +0,0 @@
/* gprs_ms.cpp
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gprs_ms.h"
#include "bts.h"
#include "tbf.h"
#include "tbf_ul.h"
#include "gprs_debug.h"
#include "gprs_codel.h"
#include "pcu_utils.h"
#include <time.h>
extern "C" {
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/core/logging.h>
#include "coding_scheme.h"
}
#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
extern void *tall_pcu_ctx;
static int64_t now_msec()
{
struct timespec ts;
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
return int64_t(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
}
struct GprsMsDefaultCallback: public GprsMs::Callback {
virtual void ms_idle(class GprsMs *ms) {
delete ms;
}
virtual void ms_active(class GprsMs *) {}
};
static GprsMsDefaultCallback gprs_default_cb;
GprsMs::Guard::Guard(GprsMs *ms) :
m_ms(ms ? ms->ref() : NULL)
{
}
GprsMs::Guard::~Guard()
{
if (m_ms)
m_ms->unref();
}
bool GprsMs::Guard::is_idle() const
{
if (!m_ms)
return true;
return !m_ms->m_ul_tbf && !m_ms->m_dl_tbf && m_ms->m_ref == 1;
}
void GprsMs::timeout(void *priv_)
{
GprsMs *ms = static_cast<GprsMs *>(priv_);
LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",
ms->tlli());
if (ms->m_timer.data) {
ms->m_timer.data = NULL;
ms->unref();
}
}
GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
m_bts(bts),
m_cb(&gprs_default_cb),
m_ul_tbf(NULL),
m_dl_tbf(NULL),
m_tlli(tlli),
m_new_ul_tlli(GSM_RESERVED_TMSI),
m_new_dl_tlli(GSM_RESERVED_TMSI),
m_ta(GSM48_TA_INVALID),
m_ms_class(0),
m_egprs_ms_class(0),
m_current_cs_ul(UNKNOWN),
m_current_cs_dl(UNKNOWN),
m_is_idle(true),
m_ref(0),
m_list(this),
m_delay(0),
m_nack_rate_dl(0),
m_reserved_dl_slots(0),
m_reserved_ul_slots(0),
m_current_trx(NULL),
m_codel_state(NULL),
m_mode(GPRS),
m_dl_ctrl_msg(0)
{
int codel_interval = LLC_CODEL_USE_DEFAULT;
LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
m_imsi[0] = '\0';
memset(&m_timer, 0, sizeof(m_timer));
m_timer.cb = GprsMs::timeout;
m_llc_queue.init();
set_mode(m_mode);
if (m_bts)
codel_interval = m_bts->bts_data()->llc_codel_interval_msec;
if (codel_interval) {
if (codel_interval == LLC_CODEL_USE_DEFAULT)
codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;
m_codel_state = talloc(this, struct gprs_codel);
gprs_codel_init(m_codel_state);
gprs_codel_set_interval(m_codel_state, codel_interval);
}
m_last_cs_not_low = now_msec();
app_info_pending = false;
}
GprsMs::~GprsMs()
{
LListHead<gprs_rlcmac_tbf> *pos, *tmp;
LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", tlli());
set_reserved_slots(NULL, 0, 0);
if (osmo_timer_pending(&m_timer))
osmo_timer_del(&m_timer);
if (m_ul_tbf) {
m_ul_tbf->set_ms(NULL);
m_ul_tbf = NULL;
}
if (m_dl_tbf) {
m_dl_tbf->set_ms(NULL);
m_dl_tbf = NULL;
}
llist_for_each_safe(pos, tmp, &m_old_tbfs)
pos->entry()->set_ms(NULL);
m_llc_queue.clear(m_bts);
}
void* GprsMs::operator new(size_t size)
{
static void *tall_ms_ctx = NULL;
if (!tall_ms_ctx)
tall_ms_ctx = talloc_named_const(tall_pcu_ctx, 0, __PRETTY_FUNCTION__);
return talloc_size(tall_ms_ctx, size);
}
void GprsMs::operator delete(void* p)
{
talloc_free(p);
}
GprsMs *GprsMs::ref()
{
m_ref += 1;
return this;
}
void GprsMs::unref()
{
OSMO_ASSERT(m_ref >= 0);
m_ref -= 1;
if (m_ref == 0)
update_status();
}
void GprsMs::start_timer()
{
if (m_delay == 0)
return;
if (!m_timer.data)
m_timer.data = ref();
osmo_timer_schedule(&m_timer, m_delay, 0);
}
void GprsMs::stop_timer()
{
if (!m_timer.data)
return;
osmo_timer_del(&m_timer);
m_timer.data = NULL;
unref();
}
void GprsMs::set_mode(enum mcs_kind mode)
{
m_mode = mode;
if (!m_bts)
return;
switch (m_mode) {
case GPRS:
if (!mcs_is_gprs(m_current_cs_ul)) {
m_current_cs_ul = mcs_get_gprs_by_num(
m_bts->bts_data()->initial_cs_ul);
if (!mcs_is_valid(m_current_cs_ul))
m_current_cs_ul = CS1;
}
if (!mcs_is_gprs(m_current_cs_dl)) {
m_current_cs_dl = mcs_get_gprs_by_num(
m_bts->bts_data()->initial_cs_dl);
if (!mcs_is_valid(m_current_cs_dl))
m_current_cs_dl = CS1;
}
break;
case EGPRS_GMSK:
case EGPRS:
if (!mcs_is_edge(m_current_cs_ul)) {
m_current_cs_ul = mcs_get_egprs_by_num(
m_bts->bts_data()->initial_mcs_ul);
if (!mcs_is_valid(m_current_cs_ul))
m_current_cs_ul = MCS1;
}
if (!mcs_is_edge(m_current_cs_dl)) {
m_current_cs_dl = mcs_get_egprs_by_num(
m_bts->bts_data()->initial_mcs_dl);
if (!mcs_is_valid(m_current_cs_dl))
m_current_cs_dl = MCS1;
}
break;
}
}
void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)
{
if (tbf->direction == GPRS_RLCMAC_DL_TBF)
attach_dl_tbf(as_dl_tbf(tbf));
else
attach_ul_tbf(as_ul_tbf(tbf));
}
void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf)
{
if (m_ul_tbf == tbf)
return;
LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
tlli(), tbf->name());
Guard guard(this);
if (m_ul_tbf)
llist_add_tail(&m_ul_tbf->ms_list(), &m_old_tbfs);
m_ul_tbf = tbf;
if (tbf)
stop_timer();
}
void GprsMs::attach_dl_tbf(struct gprs_rlcmac_dl_tbf *tbf)
{
if (m_dl_tbf == tbf)
return;
LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
tlli(), tbf->name());
Guard guard(this);
if (m_dl_tbf)
llist_add_tail(&m_dl_tbf->ms_list(), &m_old_tbfs);
m_dl_tbf = tbf;
if (tbf)
stop_timer();
}
void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)
{
if (tbf == static_cast<gprs_rlcmac_tbf *>(m_ul_tbf)) {
m_ul_tbf = NULL;
} else if (tbf == static_cast<gprs_rlcmac_tbf *>(m_dl_tbf)) {
m_dl_tbf = NULL;
} else {
bool found = false;
LListHead<gprs_rlcmac_tbf> *pos, *tmp;
llist_for_each_safe(pos, tmp, &m_old_tbfs) {
if (pos->entry() == tbf) {
llist_del(pos);
found = true;
break;
}
}
/* Protect against recursive calls via set_ms() */
if (!found)
return;
}
LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",
tlli(), tbf->name());
if (tbf->ms() == this)
tbf->set_ms(NULL);
if (!m_dl_tbf && !m_ul_tbf) {
set_reserved_slots(NULL, 0, 0);
if (tlli() != 0)
start_timer();
}
update_status();
}
void GprsMs::update_status()
{
if (m_ref > 0)
return;
if (is_idle() && !m_is_idle) {
m_is_idle = true;
m_cb->ms_idle(this);
/* this can be deleted by now, do not access it */
return;
}
if (!is_idle() && m_is_idle) {
m_is_idle = false;
m_cb->ms_active(this);
}
}
void GprsMs::reset()
{
LOGP(DRLCMAC, LOGL_INFO,
"Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",
tlli(), imsi());
stop_timer();
m_tlli = GSM_RESERVED_TMSI;
m_new_dl_tlli = m_tlli;
m_new_ul_tlli = m_tlli;
m_imsi[0] = '\0';
}
void GprsMs::merge_old_ms(GprsMs *old_ms)
{
OSMO_ASSERT(old_ms != this);
if (strlen(imsi()) == 0 && strlen(old_ms->imsi()) != 0)
osmo_strlcpy(m_imsi, old_ms->imsi(), sizeof(m_imsi));
if (!ms_class() && old_ms->ms_class())
set_ms_class(old_ms->ms_class());
if (!egprs_ms_class() && old_ms->egprs_ms_class())
set_egprs_ms_class(old_ms->egprs_ms_class());
m_llc_queue.move_and_merge(&old_ms->m_llc_queue);
old_ms->reset();
}
void GprsMs::merge_and_clear_ms(GprsMs *old_ms)
{
OSMO_ASSERT(old_ms != this);
GprsMs::Guard guard_old(old_ms);
/* Clean up the old MS object */
/* TODO: Use timer? */
if (old_ms->ul_tbf() && !old_ms->ul_tbf()->timers_pending(T_MAX))
tbf_free(old_ms->ul_tbf());
if (old_ms->dl_tbf() && !old_ms->dl_tbf()->timers_pending(T_MAX))
tbf_free(old_ms->dl_tbf());
merge_old_ms(old_ms);
}
void GprsMs::set_tlli(uint32_t tlli)
{
if (tlli == m_tlli || tlli == m_new_ul_tlli)
return;
if (tlli != m_new_dl_tlli) {
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
"not yet confirmed\n",
this->tlli(), tlli);
m_new_ul_tlli = tlli;
return;
}
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
"already confirmed partly\n",
m_tlli, tlli);
m_tlli = tlli;
m_new_dl_tlli = GSM_RESERVED_TMSI;
m_new_ul_tlli = GSM_RESERVED_TMSI;
}
bool GprsMs::confirm_tlli(uint32_t tlli)
{
if (tlli == m_tlli || tlli == m_new_dl_tlli)
return false;
if (tlli != m_new_ul_tlli) {
/* The MS has not sent a message with the new TLLI, which may
* happen according to the spec [TODO: add reference]. */
LOGP(DRLCMAC, LOGL_INFO,
"The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
"partly confirmed\n", tlli);
/* Use the network's idea of TLLI as candidate, this does not
* change the result value of tlli() */
m_new_dl_tlli = tlli;
return false;
}
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
m_tlli = tlli;
m_new_dl_tlli = GSM_RESERVED_TMSI;
m_new_ul_tlli = GSM_RESERVED_TMSI;
return true;
}
void GprsMs::set_imsi(const char *imsi)
{
if (!imsi) {
LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
return;
}
if (imsi[0] && strlen(imsi) < 3) {
LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
imsi);
return;
}
if (strcmp(imsi, m_imsi) == 0)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
tlli(), m_imsi, imsi);
GprsMs *old_ms = m_bts->ms_store().get_ms(0, 0, imsi);
/* Check if we are going to store a different MS object with already
existing IMSI. This is probably a bug in code calling this function,
since it should take care of this explicitly */
if (old_ms) {
/* We cannot find m_ms by IMSI since we know that it has a
* different IMSI */
OSMO_ASSERT(old_ms != this);
LOGPMS(this, DRLCMAC, LOGL_NOTICE,
"IMSI '%s' was already assigned to another "
"MS object: TLLI = 0x%08x, that IMSI will be removed\n",
imsi, old_ms->tlli());
merge_and_clear_ms(old_ms);
}
osmo_strlcpy(m_imsi, imsi, sizeof(m_imsi));
}
void GprsMs::set_ta(uint8_t ta_)
{
if (ta_ == m_ta)
return;
if (gsm48_ta_is_valid(ta_)) {
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
tlli(), m_ta, ta_);
m_ta = ta_;
} else
LOGP(DRLCMAC, LOGL_NOTICE,
"MS object, TLLI = 0x%08x, invalid TA %d rejected (old "
"value %d kept)\n", tlli(), ta_, m_ta);
}
void GprsMs::set_ms_class(uint8_t ms_class_)
{
if (ms_class_ == m_ms_class)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
tlli(), m_ms_class, ms_class_);
m_ms_class = ms_class_;
}
void GprsMs::set_egprs_ms_class(uint8_t ms_class_)
{
if (ms_class_ == m_egprs_ms_class)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",
tlli(), m_egprs_ms_class, ms_class_);
m_egprs_ms_class = ms_class_;
if (!m_bts->max_mcs_ul() || !m_bts->max_mcs_dl()) {
LOGPMS(this, DRLCMAC, LOGL_DEBUG,
"Avoid enabling EGPRS because use of MCS is disabled: ul=%u dl=%u\n",
m_bts->max_mcs_ul(), m_bts->max_mcs_dl());
return;
}
if (mcs_is_edge_gmsk(mcs_get_egprs_by_num(m_bts->max_mcs_ul())) &&
mcs_is_edge_gmsk(mcs_get_egprs_by_num(m_bts->max_mcs_dl())) &&
mode() != EGPRS)
{
set_mode(EGPRS_GMSK);
} else {
set_mode(EGPRS);
}
LOGPMS(this, DRLCMAC, LOGL_INFO, "Enabled EGPRS, mode %s\n", mode_name(mode()));
}
void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
{
struct gprs_rlcmac_bts *bts_data;
int64_t now;
enum CodingScheme max_cs_dl = this->max_cs_dl();
OSMO_ASSERT(max_cs_dl);
bts_data = m_bts->bts_data();
if (error_rate < 0)
return;
now = now_msec();
/* TODO: Check for TBF direction */
/* TODO: Support different CS values for UL and DL */
m_nack_rate_dl = error_rate;
if (error_rate > bts_data->cs_adj_upper_limit) {
if (mcs_chan_code(m_current_cs_dl) > 0) {
mcs_dec_kind(&m_current_cs_dl, mode());
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): High error rate %d%%, "
"reducing CS level to %s\n",
imsi(), error_rate, mcs_name(m_current_cs_dl));
m_last_cs_not_low = now;
}
} else if (error_rate < bts_data->cs_adj_lower_limit) {
if (m_current_cs_dl < max_cs_dl) {
if (now - m_last_cs_not_low > 1000) {
mcs_inc_kind(&m_current_cs_dl, mode());
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): Low error rate %d%%, "
"increasing DL CS level to %s\n",
imsi(), error_rate,
mcs_name(m_current_cs_dl));
m_last_cs_not_low = now;
} else {
LOGP(DRLCMACDL, LOGL_DEBUG,
"MS (IMSI %s): Low error rate %d%%, "
"ignored (within blocking period)\n",
imsi(), error_rate);
}
}
} else {
LOGP(DRLCMACDL, LOGL_DEBUG,
"MS (IMSI %s): Medium error rate %d%%, ignored\n",
imsi(), error_rate);
m_last_cs_not_low = now;
}
}
enum CodingScheme GprsMs::max_cs_ul() const
{
OSMO_ASSERT(m_bts != NULL);
if (mcs_is_gprs(m_current_cs_ul)) {
if (!m_bts->max_cs_ul()) {
return CS4;
}
return mcs_get_gprs_by_num(m_bts->max_cs_ul());
}
if (!mcs_is_edge(m_current_cs_ul))
return UNKNOWN;
if (m_bts->max_mcs_ul())
return mcs_get_egprs_by_num(m_bts->max_mcs_ul());
else if (m_bts->max_cs_ul())
return mcs_get_gprs_by_num(m_bts->max_cs_ul());
return MCS4;
}
void GprsMs::set_current_cs_dl(enum CodingScheme scheme)
{
m_current_cs_dl = scheme;
}
enum CodingScheme GprsMs::max_cs_dl() const
{
OSMO_ASSERT(m_bts != NULL);
if (mcs_is_gprs(m_current_cs_dl)) {
if (!m_bts->max_cs_dl()) {
return CS4;
}
return mcs_get_gprs_by_num(m_bts->max_cs_dl());
}
if (!mcs_is_edge(m_current_cs_dl))
return UNKNOWN;
if (m_bts->max_mcs_dl())
return mcs_get_egprs_by_num(m_bts->max_mcs_dl());
else if (m_bts->max_cs_dl())
return mcs_get_gprs_by_num(m_bts->max_cs_dl());
return MCS4;
}
void GprsMs::update_cs_ul(const pcu_l1_meas *meas)
{
struct gprs_rlcmac_bts *bts_data;
enum CodingScheme max_cs_ul = this->max_cs_ul();
int old_link_qual;
int low;
int high;
enum CodingScheme new_cs_ul = m_current_cs_ul;
uint8_t current_cs = mcs_chan_code(m_current_cs_ul);
bts_data = m_bts->bts_data();
if (!max_cs_ul) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"max_cs_ul cannot be derived (current UL CS: %s)\n",
mcs_name(m_current_cs_ul));
return;
}
if (!m_current_cs_ul) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS because it's not set: %s\n",
mcs_name(m_current_cs_ul));
return;
}
if (!meas->have_link_qual) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS %s because we don't have link quality measurements.\n",
mcs_name(m_current_cs_ul));
return;
}
if (mcs_is_gprs(m_current_cs_ul)) {
if (current_cs >= MAX_GPRS_CS)
current_cs = MAX_GPRS_CS - 1;
low = bts_data->cs_lqual_ranges[current_cs].low;
high = bts_data->cs_lqual_ranges[current_cs].high;
} else if (mcs_is_edge(m_current_cs_ul)) {
if (current_cs >= MAX_EDGE_MCS)
current_cs = MAX_EDGE_MCS - 1;
low = bts_data->mcs_lqual_ranges[current_cs].low;
high = bts_data->mcs_lqual_ranges[current_cs].high;
} else {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",
mcs_name(m_current_cs_ul));
return;
}
/* To avoid rapid changes of the coding scheme, we also take
* the old link quality value into account (if present). */
if (m_l1_meas.have_link_qual)
old_link_qual = m_l1_meas.link_qual;
else
old_link_qual = meas->link_qual;
if (meas->link_qual < low && old_link_qual < low)
mcs_dec_kind(&new_cs_ul, mode());
else if (meas->link_qual > high && old_link_qual > high &&
m_current_cs_ul < max_cs_ul)
mcs_inc_kind(&new_cs_ul, mode());
if (m_current_cs_ul != new_cs_ul) {
LOGPMS(this, DRLCMACMEAS, LOGL_INFO,
"Link quality %ddB (old %ddB) left window [%d, %d], "
"modifying uplink CS level: %s -> %s\n",
meas->link_qual, old_link_qual,
low, high,
mcs_name(m_current_cs_ul), mcs_name(new_cs_ul));
m_current_cs_ul = new_cs_ul;
}
}
void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
{
unsigned i;
update_cs_ul(meas);
if (meas->have_rssi)
m_l1_meas.set_rssi(meas->rssi);
if (meas->have_bto)
m_l1_meas.set_bto(meas->bto);
if (meas->have_ber)
m_l1_meas.set_ber(meas->ber);
if (meas->have_link_qual)
m_l1_meas.set_link_qual(meas->link_qual);
if (meas->have_ms_rx_qual)
m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual);
if (meas->have_ms_c_value)
m_l1_meas.set_ms_c_value(meas->ms_c_value);
if (meas->have_ms_sign_var)
m_l1_meas.set_ms_sign_var(meas->ms_sign_var);
if (meas->have_ms_i_level) {
for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
if (meas->ts[i].have_ms_i_level)
m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level);
else
m_l1_meas.ts[i].have_ms_i_level = 0;
}
}
}
enum CodingScheme GprsMs::current_cs_dl() const
{
enum CodingScheme cs = m_current_cs_dl;
size_t unencoded_octets;
if (!m_bts)
return cs;
unencoded_octets = m_llc_queue.octets();
/* If the DL TBF is active, add number of unencoded chunk octets */
if (m_dl_tbf)
unencoded_octets += m_dl_tbf->m_llc.chunk_size();
/* There are many unencoded octets, don't reduce */
if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)
return cs;
/* RF conditions are good, don't reduce */
if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit)
return cs;
/* The throughput would probably be better if the CS level was reduced */
mcs_dec_kind(&cs, mode());
/* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
if (cs == CS2)
mcs_dec_kind(&cs, mode());
return cs;
}
int GprsMs::first_common_ts() const
{
if (m_dl_tbf)
return m_dl_tbf->first_common_ts;
if (m_ul_tbf)
return m_ul_tbf->first_common_ts;
return -1;
}
uint8_t GprsMs::dl_slots() const
{
uint8_t slots = 0;
if (m_dl_tbf)
slots |= m_dl_tbf->dl_slots();
if (m_ul_tbf)
slots |= m_ul_tbf->dl_slots();
return slots;
}
uint8_t GprsMs::ul_slots() const
{
uint8_t slots = 0;
if (m_dl_tbf)
slots |= m_dl_tbf->ul_slots();
if (m_ul_tbf)
slots |= m_ul_tbf->ul_slots();
return slots;
}
uint8_t GprsMs::current_pacch_slots() const
{
uint8_t slots = 0;
bool is_dl_active = m_dl_tbf && m_dl_tbf->is_tfi_assigned();
bool is_ul_active = m_ul_tbf && m_ul_tbf->is_tfi_assigned();
if (!is_dl_active && !is_ul_active)
return 0;
/* see TS 44.060, 8.1.1.2.2 */
if (is_dl_active && !is_ul_active)
slots = m_dl_tbf->dl_slots();
else if (!is_dl_active && is_ul_active)
slots = m_ul_tbf->ul_slots();
else
slots = m_ul_tbf->ul_slots() & m_dl_tbf->dl_slots();
/* Assume a multislot class 1 device */
/* TODO: For class 2 devices, this could be removed */
slots = pcu_lsb(slots);
return slots;
}
void GprsMs::set_reserved_slots(gprs_rlcmac_trx *trx,
uint8_t ul_slots, uint8_t dl_slots)
{
if (m_current_trx) {
m_current_trx->unreserve_slots(GPRS_RLCMAC_DL_TBF,
m_reserved_dl_slots);
m_current_trx->unreserve_slots(GPRS_RLCMAC_UL_TBF,
m_reserved_ul_slots);
m_reserved_dl_slots = 0;
m_reserved_ul_slots = 0;
}
m_current_trx = trx;
if (trx) {
m_reserved_dl_slots = dl_slots;
m_reserved_ul_slots = ul_slots;
m_current_trx->reserve_slots(GPRS_RLCMAC_DL_TBF,
m_reserved_dl_slots);
m_current_trx->reserve_slots(GPRS_RLCMAC_UL_TBF,
m_reserved_ul_slots);
}
}
gprs_rlcmac_tbf *GprsMs::tbf(enum gprs_rlcmac_tbf_direction dir) const
{
switch (dir) {
case GPRS_RLCMAC_DL_TBF: return m_dl_tbf;
case GPRS_RLCMAC_UL_TBF: return m_ul_tbf;
}
return NULL;
}

View File

@ -1,6 +1,6 @@
/* gprs_ms.h
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Copyright (C) 2015-2020 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
@ -22,22 +22,23 @@
struct gprs_codel;
#include "cxx_linuxlist.h"
#include "llc.h"
#include "tbf.h"
#include "tbf_ul.h"
#include "tbf_dl.h"
#include "pcu_l1_if.h"
#ifdef __cplusplus
extern "C" {
#include <osmocom/core/timer.h>
#include <osmocom/core/linuxlist.h>
#endif
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/linuxlist.h>
#include "coding_scheme.h"
}
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/gsm/gsm48.h>
#include "coding_scheme.h"
#include <stdint.h>
#include <stddef.h>
@ -45,268 +46,207 @@ extern "C" {
struct BTS;
struct gprs_rlcmac_trx;
struct GprsMs;
class GprsMs {
public:
struct Callback {
virtual void ms_idle(class GprsMs *) = 0;
virtual void ms_active(class GprsMs *) = 0;
};
class Guard {
public:
Guard(GprsMs *ms);
~Guard();
bool is_idle() const;
private:
GprsMs * const m_ms;
};
GprsMs(BTS *bts, uint32_t tlli);
~GprsMs();
void set_callback(Callback *cb) {m_cb = cb;}
void merge_and_clear_ms(GprsMs *old_ms);
gprs_rlcmac_ul_tbf *ul_tbf() const {return m_ul_tbf;}
gprs_rlcmac_dl_tbf *dl_tbf() const {return m_dl_tbf;}
gprs_rlcmac_tbf *tbf(enum gprs_rlcmac_tbf_direction dir) const;
uint32_t tlli() const;
void set_tlli(uint32_t tlli);
bool confirm_tlli(uint32_t tlli);
bool check_tlli(uint32_t tlli);
void reset();
enum mcs_kind mode() const;
void set_mode(enum mcs_kind mode);
const char *imsi() const;
void set_imsi(const char *imsi);
uint8_t ta() const;
void set_ta(uint8_t ta);
uint8_t ms_class() const;
uint8_t egprs_ms_class() const;
void set_ms_class(uint8_t ms_class);
void set_egprs_ms_class(uint8_t ms_class);
void set_current_cs_dl(enum CodingScheme scheme);
enum CodingScheme current_cs_ul() const;
enum CodingScheme current_cs_dl() const;
enum CodingScheme max_cs_ul() const;
enum CodingScheme max_cs_dl() const;
int first_common_ts() const;
uint8_t dl_slots() const;
uint8_t ul_slots() const;
uint8_t reserved_dl_slots() const;
uint8_t reserved_ul_slots() const;
uint8_t current_pacch_slots() const;
gprs_rlcmac_trx *current_trx() const;
void set_reserved_slots(gprs_rlcmac_trx *trx,
uint8_t ul_slots, uint8_t dl_slots);
gprs_llc_queue *llc_queue();
const gprs_llc_queue *llc_queue() const;
gprs_codel *codel_state() const;
void set_timeout(unsigned secs);
void attach_tbf(gprs_rlcmac_tbf *tbf);
void attach_ul_tbf(gprs_rlcmac_ul_tbf *tbf);
void attach_dl_tbf(gprs_rlcmac_dl_tbf *tbf);
void detach_tbf(gprs_rlcmac_tbf *tbf);
void update_error_rate(gprs_rlcmac_tbf *tbf, int percent);
bool is_idle() const;
bool need_dl_tbf() const;
void* operator new(size_t num);
void operator delete(void* p);
LListHead<GprsMs>& list() {return this->m_list;}
const LListHead<GprsMs>& list() const {return this->m_list;}
const LListHead<gprs_rlcmac_tbf>& old_tbfs() const {return m_old_tbfs;}
void update_l1_meas(const pcu_l1_meas *meas);
const pcu_l1_meas* l1_meas() const {return &m_l1_meas;};
unsigned nack_rate_dl() const;
unsigned dl_ctrl_msg() const;
void update_dl_ctrl_msg();
/* internal use */
static void timeout(void *priv_);
bool app_info_pending;
protected:
void merge_old_ms(GprsMs *old_ms);
void update_status();
GprsMs *ref();
void unref();
void start_timer();
void stop_timer();
void update_cs_ul(const pcu_l1_meas*);
private:
BTS *m_bts;
Callback * m_cb;
gprs_rlcmac_ul_tbf *m_ul_tbf;
gprs_rlcmac_dl_tbf *m_dl_tbf;
LListHead<gprs_rlcmac_tbf> m_old_tbfs;
uint32_t m_tlli;
uint32_t m_new_ul_tlli;
uint32_t m_new_dl_tlli;
/* store IMSI for look-up and PCH retransmission */
char m_imsi[OSMO_IMSI_BUF_SIZE];
uint8_t m_ta;
uint8_t m_ms_class;
uint8_t m_egprs_ms_class;
/* current coding scheme */
enum CodingScheme m_current_cs_ul;
enum CodingScheme m_current_cs_dl;
gprs_llc_queue m_llc_queue;
bool m_is_idle;
int m_ref;
LListHead<GprsMs> m_list;
struct osmo_timer_list m_timer;
unsigned m_delay;
int64_t m_last_cs_not_low;
pcu_l1_meas m_l1_meas;
unsigned m_nack_rate_dl;
uint8_t m_reserved_dl_slots;
uint8_t m_reserved_ul_slots;
gprs_rlcmac_trx *m_current_trx;
struct gprs_codel *m_codel_state;
enum mcs_kind m_mode;
unsigned m_dl_ctrl_msg;
struct gpr_ms_callback {
void (*ms_idle)(struct GprsMs *);
void (*ms_active)(struct GprsMs *);
};
inline bool GprsMs::is_idle() const
struct GprsMs {
struct llist_head list; /* list of all GprsMs */
struct gpr_ms_callback cb;
bool app_info_pending;
struct BTS *bts;
struct gprs_rlcmac_ul_tbf *ul_tbf;
struct gprs_rlcmac_dl_tbf *dl_tbf;
struct llist_head old_tbfs; /* list of gprs_rlcmac_tbf */
uint32_t tlli;
uint32_t new_ul_tlli;
uint32_t new_dl_tlli;
/* store IMSI for look-up and PCH retransmission */
char imsi[OSMO_IMSI_BUF_SIZE];
uint8_t ta;
uint8_t ms_class;
uint8_t egprs_ms_class;
/* current coding scheme */
enum CodingScheme current_cs_ul;
enum CodingScheme current_cs_dl;
struct gprs_llc_queue llc_queue;
bool is_idle;
int ref;
struct osmo_timer_list timer;
unsigned delay;
int64_t last_cs_not_low;
struct pcu_l1_meas l1_meas;
unsigned nack_rate_dl;
uint8_t reserved_dl_slots;
uint8_t reserved_ul_slots;
struct gprs_rlcmac_trx *current_trx;
struct gprs_codel *codel_state;
enum mcs_kind mode;
unsigned dl_ctrl_msg;
};
struct GprsMs *ms_alloc(struct BTS *bts, uint32_t tlli);
int ms_first_common_ts(const struct GprsMs *ms);
void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,
uint8_t ul_slots, uint8_t dl_slots);
struct GprsMs *ms_ref(struct GprsMs *ms);
void ms_unref(struct GprsMs *ms);
void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode);
void ms_set_ms_class(struct GprsMs *ms, uint8_t ms_class_);
void ms_set_egprs_ms_class(struct GprsMs *ms, uint8_t ms_class_);
void ms_set_ta(struct GprsMs *ms, uint8_t ta_);
enum CodingScheme ms_current_cs_dl(const struct GprsMs *ms);
enum CodingScheme ms_max_cs_ul(const struct GprsMs *ms);
enum CodingScheme ms_max_cs_dl(const struct GprsMs *ms);
void ms_set_current_cs_dl(struct GprsMs *ms, enum CodingScheme scheme);
void ms_update_error_rate(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, int error_rate);
uint8_t ms_current_pacch_slots(const struct GprsMs *ms);
void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms);
void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);
void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);
void ms_set_tlli(struct GprsMs *ms, uint32_t tlli);
bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli);
void ms_set_imsi(struct GprsMs *ms, const char *imsi);
void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas);
struct gprs_rlcmac_tbf *ms_tbf(const struct GprsMs *ms, enum gprs_rlcmac_tbf_direction dir);
static inline struct gprs_rlcmac_ul_tbf *ms_ul_tbf(const struct GprsMs *ms) {return ms->ul_tbf;}
static inline struct gprs_rlcmac_dl_tbf *ms_dl_tbf(const struct GprsMs *ms) {return ms->dl_tbf;}
void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb);
static inline bool ms_is_idle(const struct GprsMs *ms)
{
return !m_ul_tbf && !m_dl_tbf && !m_ref && llist_empty(&m_old_tbfs);
return !ms->ul_tbf && !ms->dl_tbf && !ms->ref && llist_empty(&ms->old_tbfs);
}
inline bool GprsMs::need_dl_tbf() const
static inline struct gprs_llc_queue *ms_llc_queue(struct GprsMs *ms)
{
if (dl_tbf() != NULL && dl_tbf()->state_is_not(GPRS_RLCMAC_WAIT_RELEASE))
return &ms->llc_queue;
}
static inline bool ms_need_dl_tbf(struct GprsMs *ms)
{
if (ms_dl_tbf(ms) != NULL &&
tbf_state((const struct gprs_rlcmac_tbf *)ms_dl_tbf(ms)) != GPRS_RLCMAC_WAIT_RELEASE)
return false;
return llc_queue()->size() > 0;
return llc_queue_size(ms_llc_queue(ms)) > 0;
}
inline uint32_t GprsMs::tlli() const
static inline uint32_t ms_tlli(const struct GprsMs *ms)
{
if (m_new_ul_tlli != GSM_RESERVED_TMSI)
return m_new_ul_tlli;
if (m_tlli != GSM_RESERVED_TMSI)
return m_tlli;
if (ms->new_ul_tlli != GSM_RESERVED_TMSI)
return ms->new_ul_tlli;
if (ms->tlli != GSM_RESERVED_TMSI)
return ms->tlli;
return m_new_dl_tlli;
return ms->new_dl_tlli;
}
inline bool GprsMs::check_tlli(uint32_t tlli)
static inline bool ms_check_tlli(struct GprsMs *ms, uint32_t tlli)
{
return tlli != GSM_RESERVED_TMSI &&
(tlli == m_tlli || tlli == m_new_ul_tlli || tlli == m_new_dl_tlli);
(tlli == ms->tlli || tlli == ms->new_ul_tlli || tlli == ms->new_dl_tlli);
}
inline const char *GprsMs::imsi() const
static inline const char *ms_imsi(const struct GprsMs *ms)
{
return m_imsi;
return ms->imsi;
}
inline uint8_t GprsMs::ta() const
static inline uint8_t ms_ta(const struct GprsMs *ms)
{
return m_ta;
return ms->ta;
}
inline uint8_t GprsMs::ms_class() const
static inline uint8_t ms_ms_class(const struct GprsMs *ms)
{
return m_ms_class;
return ms->ms_class;
}
inline uint8_t GprsMs::egprs_ms_class() const
static inline uint8_t ms_egprs_ms_class(const struct GprsMs *ms)
{
return m_egprs_ms_class;
return ms->egprs_ms_class;
}
inline enum CodingScheme GprsMs::current_cs_ul() const
static inline enum CodingScheme ms_current_cs_ul(const struct GprsMs *ms)
{
return m_current_cs_ul;
return ms->current_cs_ul;
}
inline enum mcs_kind GprsMs::mode() const
static inline enum mcs_kind ms_mode(const struct GprsMs *ms)
{
return m_mode;
return ms->mode;
}
inline void GprsMs::set_timeout(unsigned secs)
static inline void ms_set_timeout(struct GprsMs *ms, unsigned secs)
{
m_delay = secs;
ms->delay = secs;
}
inline gprs_llc_queue *GprsMs::llc_queue()
static inline struct gprs_codel *ms_codel_state(const struct GprsMs *ms)
{
return &m_llc_queue;
return ms->codel_state;
}
inline const gprs_llc_queue *GprsMs::llc_queue() const
static inline unsigned ms_nack_rate_dl(const struct GprsMs *ms)
{
return &m_llc_queue;
return ms->nack_rate_dl;
}
inline gprs_codel *GprsMs::codel_state() const
static inline unsigned ms_dl_ctrl_msg(const struct GprsMs *ms)
{
return m_codel_state;
return ms->dl_ctrl_msg;
}
inline unsigned GprsMs::nack_rate_dl() const
static inline void ms_update_dl_ctrl_msg(struct GprsMs *ms)
{
return m_nack_rate_dl;
ms->dl_ctrl_msg++;
}
inline unsigned GprsMs::dl_ctrl_msg() const
static inline uint8_t ms_reserved_dl_slots(const struct GprsMs *ms)
{
return m_dl_ctrl_msg;
return ms->reserved_dl_slots;
}
inline void GprsMs::update_dl_ctrl_msg()
static inline uint8_t ms_reserved_ul_slots(const struct GprsMs *ms)
{
m_dl_ctrl_msg++;
return ms->reserved_ul_slots;
}
inline uint8_t GprsMs::reserved_dl_slots() const
static inline struct gprs_rlcmac_trx *ms_current_trx(const struct GprsMs *ms)
{
return m_reserved_dl_slots;
}
inline uint8_t GprsMs::reserved_ul_slots() const
{
return m_reserved_ul_slots;
}
inline gprs_rlcmac_trx *GprsMs::current_trx() const
{
return m_current_trx;
return ms->current_trx;
}
#define LOGPMS(ms, category, level, fmt, args...) \
LOGP(category, level, "MS(TLLI=0x%08x, IMSI=%s, TA=%" PRIu8 ", %" PRIu8 "/%" PRIu8 ",%s%s) " fmt, \
(ms)->tlli(), (ms)->imsi(), (ms)->ta(), (ms)->ms_class(), (ms)->egprs_ms_class(), \
(ms)->ul_tbf() ? " UL": "", \
(ms)->dl_tbf() ? " DL": "", \
ms_tlli(ms), ms_imsi(ms), ms_ta(ms), ms_ms_class(ms), ms_egprs_ms_class(ms), \
ms_ul_tbf(ms) ? " UL": "", \
ms_dl_tbf(ms) ? " DL": "", \
## args)
#ifdef __cplusplus
}
#endif

View File

@ -31,9 +31,29 @@ extern "C" {
#define GPRS_UNDEFINED_IMSI "000"
static void ms_storage_ms_idle_cb(struct GprsMs *ms)
{
llist_del(&ms->list);
if (ms->bts)
ms->bts->stat_item_add(STAT_MS_PRESENT, -1);
if (ms_is_idle(ms))
talloc_free(ms);
}
static void ms_storage_ms_active_cb(struct GprsMs *ms)
{
/* Nothing to do */
}
static struct gpr_ms_callback ms_storage_ms_cb = {
.ms_idle = ms_storage_ms_idle_cb,
.ms_active = ms_storage_ms_active_cb,
};
GprsMsStorage::GprsMsStorage(BTS *bts) :
m_bts(bts)
{
INIT_LLIST_HEAD(&m_list);
}
GprsMsStorage::~GprsMsStorage()
@ -43,40 +63,26 @@ GprsMsStorage::~GprsMsStorage()
void GprsMsStorage::cleanup()
{
LListHead<GprsMs> *pos, *tmp;
struct llist_head *pos, *tmp;
llist_for_each_safe(pos, tmp, &m_list) {
GprsMs *ms = pos->entry();
ms->set_callback(NULL);
ms_idle(ms);
struct GprsMs *ms = llist_entry(pos, typeof(*ms), list);
ms_set_callback(ms, NULL);
ms_storage_ms_idle_cb(ms);
}
}
void GprsMsStorage::ms_idle(class GprsMs *ms)
{
llist_del(&ms->list());
if (m_bts)
m_bts->stat_item_add(STAT_MS_PRESENT, -1);
if (ms->is_idle())
delete ms;
}
void GprsMsStorage::ms_active(class GprsMs *ms)
{
/* Nothing to do */
}
GprsMs *GprsMsStorage::get_ms(uint32_t tlli, uint32_t old_tlli, const char *imsi) const
{
struct llist_head *tmp;
GprsMs *ms;
LListHead<GprsMs> *pos;
if (tlli != GSM_RESERVED_TMSI || old_tlli != GSM_RESERVED_TMSI) {
llist_for_each(pos, &m_list) {
ms = pos->entry();
if (ms->check_tlli(tlli))
llist_for_each(tmp, &m_list) {
ms = llist_entry(tmp, typeof(*ms), list);
if (ms_check_tlli(ms, tlli))
return ms;
if (ms->check_tlli(old_tlli))
if (ms_check_tlli(ms, old_tlli))
return ms;
}
}
@ -84,9 +90,9 @@ GprsMs *GprsMsStorage::get_ms(uint32_t tlli, uint32_t old_tlli, const char *imsi
/* not found by TLLI */
if (imsi && imsi[0] && strcmp(imsi, GPRS_UNDEFINED_IMSI) != 0) {
llist_for_each(pos, &m_list) {
ms = pos->entry();
if (strcmp(imsi, ms->imsi()) == 0)
llist_for_each(tmp, &m_list) {
ms = llist_entry(tmp, typeof(*ms), list);
if (strcmp(imsi, ms_imsi(ms)) == 0)
return ms;
}
}
@ -98,10 +104,10 @@ GprsMs *GprsMsStorage::create_ms()
{
GprsMs *ms;
ms = new GprsMs(m_bts, GSM_RESERVED_TMSI);
ms = ms_alloc(m_bts, GSM_RESERVED_TMSI);
ms->set_callback(this);
llist_add(&ms->list(), &m_list);
ms_set_callback(ms, &ms_storage_ms_cb);
llist_add(&ms->list, &m_list);
if (m_bts)
m_bts->stat_item_add(STAT_MS_PRESENT, 1);

View File

@ -21,28 +21,24 @@
#pragma once
#include "gprs_ms.h"
#include "cxx_linuxlist.h"
#include "tbf.h"
#include <stdint.h>
#include <stddef.h>
struct BTS;
class GprsMsStorage : public GprsMs::Callback {
class GprsMsStorage {
public:
GprsMsStorage(BTS *bts);
~GprsMsStorage();
void cleanup();
virtual void ms_idle(class GprsMs *);
virtual void ms_active(class GprsMs *);
GprsMs *get_ms(uint32_t tlli, uint32_t old_tlli = GSM_RESERVED_TMSI, const char *imsi = NULL) const;
GprsMs *create_ms();
const LListHead<GprsMs>& ms_list() const {return m_list;}
const struct llist_head* ms_list() const {return &m_list;}
private:
BTS *m_bts;
LListHead<GprsMs> m_list;
struct llist_head m_list; /* list of struct GprsMs */
};

View File

@ -234,7 +234,7 @@ static struct msgb *sched_select_ctrl_msg(
"message at RTS for %s (TRX=%d, TS=%d)\n",
tbf_name(tbf), trx, ts);
/* Updates the dl ctrl msg counter for ms */
tbf->ms()->update_dl_ctrl_msg();
ms_update_dl_ctrl_msg(tbf->ms());
return msg;
}
@ -342,7 +342,7 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
pdch->next_dl_tfi = (prio_tfi + 1) & 31;
/* generate DL data block */
msg = prio_tbf->create_dl_acked_block(fn, ts, req_mcs_kind);
*is_egprs = prio_tbf->ms()->mode() != GPRS;
*is_egprs = ms_mode(prio_tbf->ms()) != GPRS;
}
return msg;
@ -463,7 +463,7 @@ int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
* only be able to read USF if dl block uses GMSK
* (CS1-4, MCS1-4)
*/
if (req_mcs_kind == EGPRS && usf_tbf->ms()->mode() != EGPRS)
if (req_mcs_kind == EGPRS && ms_mode(usf_tbf->ms()) != EGPRS)
req_mcs_kind = EGPRS_GMSK;
} else {
usf = USF_UNUSED;

View File

@ -245,8 +245,8 @@ static int find_trx(const struct gprs_rlcmac_bts *bts_data, const GprsMs *ms, in
unsigned ts;
/* We must use the TRX currently actively used by an MS */
if (ms && ms->current_trx())
return ms->current_trx()->trx_no;
if (ms && ms_current_trx(ms))
return ms_current_trx(ms)->trx_no;
if (use_trx >= 0 && use_trx < 8)
return use_trx;
@ -320,8 +320,8 @@ static int tfi_find_free(const BTS *bts, const gprs_rlcmac_trx *trx, const GprsM
use_trx = trx->trx_no;
}
if (use_trx == -1 && ms->current_trx())
use_trx = ms->current_trx()->trx_no;
if (use_trx == -1 && ms_current_trx(ms))
use_trx = ms_current_trx(ms)->trx_no;
tfi = bts->tfi_find_free(dir, &trx_no, use_trx);
if (tfi < 0)
@ -357,7 +357,7 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, GprsMs *ms_, struct gprs_rlcm
const char *mask_reason = NULL;
const GprsMs *ms = ms_;
const gprs_rlcmac_tbf *tbf = tbf_;
gprs_rlcmac_trx *trx = ms->current_trx();
gprs_rlcmac_trx *trx = ms_current_trx(ms);
LOGPAL(tbf, "A", single, use_trx, LOGL_DEBUG, "Alloc start\n");
@ -370,10 +370,10 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, GprsMs *ms_, struct gprs_rlcm
if (!trx)
trx = &bts->trx[trx_no];
dl_slots = ms->reserved_dl_slots();
ul_slots = ms->reserved_ul_slots();
dl_slots = ms_reserved_dl_slots(ms);
ul_slots = ms_reserved_ul_slots(ms);
ts = ms->first_common_ts();
ts = ms_first_common_ts(ms);
if (ts >= 0) {
mask_reason = "need to reuse TS";
@ -420,7 +420,7 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, GprsMs *ms_, struct gprs_rlcm
tbf_->trx = trx;
/* the only one TS is the common TS */
tbf_->first_ts = tbf_->first_common_ts = ts;
ms_->set_reserved_slots(trx, 1 << ts, 1 << ts);
ms_set_reserved_slots(ms_, trx, 1 << ts, 1 << ts);
tbf_->upgrade_to_multislot = 0;
bts->bts->do_rate_ctr_inc(CTR_TBF_ALLOC_ALGO_A);
@ -774,11 +774,11 @@ static void update_ms_reserved_slots(gprs_rlcmac_trx *trx, GprsMs *ms, uint8_t r
{
char slot_info[9] = { 0 };
if (res_ul_slots == ms->reserved_ul_slots() && res_dl_slots == ms->reserved_dl_slots())
if (res_ul_slots == ms_reserved_ul_slots(ms) && res_dl_slots == ms_reserved_dl_slots(ms))
return;
/* The reserved slots have changed, update the MS */
ms->set_reserved_slots(trx, res_ul_slots, res_dl_slots);
ms_set_reserved_slots(ms, trx, res_ul_slots, res_dl_slots);
ts_format(slot_info, dl_slots, ul_slots);
LOGP(DRLCMAC, LOGL_DEBUG, "- Reserved DL/UL slots: (TS=0)\"%s\"(TS=7)\n", slot_info);
@ -867,10 +867,10 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, GprsMs *ms_, struct gprs_rlcm
return -EINVAL;
}
dl_slots = ms->reserved_dl_slots();
ul_slots = ms->reserved_ul_slots();
first_common_ts = ms->first_common_ts();
trx = ms->current_trx();
dl_slots = ms_reserved_dl_slots(ms);
ul_slots = ms_reserved_ul_slots(ms);
first_common_ts = ms_first_common_ts(ms);
trx = ms_current_trx(ms);
/* Step 2a: Find usable TRX and TFI */
tfi = tfi_find_free(bts->bts, trx, ms, tbf->direction, use_trx, &trx_no);
@ -884,7 +884,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, GprsMs *ms_, struct gprs_rlcm
trx = &bts->trx[trx_no];
if (!dl_slots || !ul_slots) {
rc = find_multi_slots(trx, ms->ms_class(), &ul_slots, &dl_slots);
rc = find_multi_slots(trx, ms_ms_class(ms), &ul_slots, &dl_slots);
if (rc < 0)
return rc;
}

View File

@ -97,12 +97,12 @@ bool gprs_llc::is_user_data_frame(uint8_t *data, size_t len)
return true;
}
void gprs_llc_queue::init()
void llc_queue_init(struct gprs_llc_queue *q)
{
INIT_LLIST_HEAD(&m_queue);
m_queue_size = 0;
m_queue_octets = 0;
m_avg_queue_delay = 0;
INIT_LLIST_HEAD(&q->m_queue);
q->m_queue_size = 0;
q->m_queue_octets = 0;
q->m_avg_queue_delay = 0;
}
@ -122,21 +122,21 @@ void gprs_llc_queue::enqueue(struct msgb *llc_msg, const struct timespec *expire
msgb_enqueue(&m_queue, llc_msg);
}
void gprs_llc_queue::clear(BTS *bts)
void llc_queue_clear(struct gprs_llc_queue *q, struct BTS *bts)
{
struct msgb *msg;
while ((msg = msgb_dequeue(&m_queue))) {
while ((msg = msgb_dequeue(&q->m_queue))) {
if (bts)
bts->do_rate_ctr_inc(CTR_LLC_FRAME_DROPPED);
msgb_free(msg);
}
m_queue_size = 0;
m_queue_octets = 0;
q->m_queue_size = 0;
q->m_queue_octets = 0;
}
void gprs_llc_queue::move_and_merge(gprs_llc_queue *o)
void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o)
{
struct msgb *msg, *msg1 = NULL, *msg2 = NULL;
struct llist_head new_queue;
@ -146,7 +146,7 @@ void gprs_llc_queue::move_and_merge(gprs_llc_queue *o)
while (1) {
if (msg1 == NULL)
msg1 = msgb_dequeue(&m_queue);
msg1 = msgb_dequeue(&q->m_queue);
if (msg2 == NULL)
msg2 = msgb_dequeue(&o->m_queue);
@ -178,15 +178,15 @@ void gprs_llc_queue::move_and_merge(gprs_llc_queue *o)
queue_octets += msgb_length(msg);
}
OSMO_ASSERT(llist_empty(&m_queue));
OSMO_ASSERT(llist_empty(&q->m_queue));
OSMO_ASSERT(llist_empty(&o->m_queue));
o->m_queue_size = 0;
o->m_queue_octets = 0;
llist_splice_init(&new_queue, &m_queue);
m_queue_size = queue_size;
m_queue_octets = queue_octets;
llist_splice_init(&new_queue, &q->m_queue);
q->m_queue_size = queue_size;
q->m_queue_octets = queue_octets;
}
#define ALPHA 0.5f

View File

@ -18,9 +18,13 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/linuxlist.h>
#ifdef __cplusplus
}
#endif
#include <stdint.h>
#include <string.h>
@ -34,6 +38,8 @@ struct BTS;
* I represent the LLC data to a MS
*/
struct gprs_llc {
#ifdef __cplusplus
static bool is_user_data_frame(uint8_t *data, size_t len);
void init();
@ -43,92 +49,86 @@ struct gprs_llc {
void put_frame(const uint8_t *data, size_t len);
void put_dummy_frame(size_t req_len);
void append_frame(const uint8_t *data, size_t len);
void consume(size_t len);
void consume(uint8_t *data, size_t len);
uint16_t chunk_size() const;
uint16_t remaining_space() const;
uint16_t frame_length() const;
bool fits_in_current_frame(uint8_t size) const;
#endif
uint8_t frame[LLC_MAX_LEN]; /* current DL or UL frame */
uint16_t m_index; /* current write/read position of frame */
uint16_t m_length; /* len of current DL LLC_frame, 0 == no frame */
};
struct MetaInfo {
struct timespec recv_time;
struct timespec expire_time;
};
/**
* I store the LLC frames that come from the SGSN.
*/
struct gprs_llc_queue {
struct MetaInfo {
struct timespec recv_time;
struct timespec expire_time;
};
#ifdef __cplusplus
static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec,
struct timespec *tv);
static bool is_frame_expired(const struct timespec *now,
const struct timespec *tv);
static bool is_user_data_frame(uint8_t *data, size_t len);
void init();
void enqueue(struct msgb *llc_msg, const struct timespec *expire_time);
struct msgb *dequeue(const MetaInfo **info = 0);
void clear(BTS *bts);
void move_and_merge(gprs_llc_queue *o);
size_t size() const;
size_t octets() const;
private:
#endif
uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */
size_t m_queue_size;
size_t m_queue_octets;
struct llist_head m_queue; /* queued LLC DL data */
};
#ifdef __cplusplus
extern "C" {
#endif
void llc_queue_init(struct gprs_llc_queue *q);
void llc_queue_clear(struct gprs_llc_queue *q, struct BTS *bts);
void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o);
inline uint16_t gprs_llc::chunk_size() const
static inline uint16_t llc_chunk_size(const struct gprs_llc *llc)
{
return m_length - m_index;
return llc->m_length - llc->m_index;
}
inline uint16_t gprs_llc::remaining_space() const
static inline uint16_t llc_remaining_space(const struct gprs_llc *llc)
{
return LLC_MAX_LEN - m_length;
return LLC_MAX_LEN - llc->m_length;
}
inline uint16_t gprs_llc::frame_length() const
static inline uint16_t llc_frame_length(const struct gprs_llc *llc)
{
return m_length;
return llc->m_length;
}
inline void gprs_llc::consume(size_t len)
static inline void llc_consume(struct gprs_llc *llc, size_t len)
{
m_index += len;
llc->m_index += len;
}
inline void gprs_llc::consume(uint8_t *data, size_t len)
static inline void llc_consume_data(struct gprs_llc *llc, uint8_t *data, size_t len)
{
/* copy and increment index */
memcpy(data, frame + m_index, len);
consume(len);
memcpy(data, llc->frame + llc->m_index, len);
llc_consume(llc, len);
}
inline bool gprs_llc::fits_in_current_frame(uint8_t chunk_size) const
static inline bool llc_fits_in_current_frame(const struct gprs_llc *llc, uint8_t chunk_size)
{
return m_length + chunk_size <= LLC_MAX_LEN;
return llc->m_length + chunk_size <= LLC_MAX_LEN;
}
inline size_t gprs_llc_queue::size() const
static inline size_t llc_queue_size(const struct gprs_llc_queue *q)
{
return m_queue_size;
return q->m_queue_size;
}
inline size_t gprs_llc_queue::octets() const
static inline size_t llc_queue_octets(const struct gprs_llc_queue *q)
{
return m_queue_octets;
return q->m_queue_octets;
}
#ifdef __cplusplus
}
#endif

View File

@ -318,7 +318,7 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
struct gprs_rlcmac_bts *bts = bts_main_data();
int rc;
int current_fn = get_current_fn();
pcu_l1_meas meas;
struct pcu_l1_meas meas = {0};
uint8_t gsmtap_chantype;
LOGP(DL1IF, LOGL_DEBUG, "Data indication received: sapi=%d arfcn=%d "
@ -328,11 +328,11 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
switch (data_ind->sapi) {
case PCU_IF_SAPI_PDTCH:
meas.set_rssi(data_ind->rssi);
pcu_l1_meas_set_rssi(&meas, data_ind->rssi);
/* convert BER to % value */
meas.set_ber(data_ind->ber10k / 100);
meas.set_bto(data_ind->ta_offs_qbits);
meas.set_link_qual(data_ind->lqual_cb / 10);
pcu_l1_meas_set_ber(&meas, data_ind->ber10k / 100);
pcu_l1_meas_set_bto(&meas, data_ind->ta_offs_qbits);
pcu_l1_meas_set_link_qual(&meas, data_ind->lqual_cb / 10);
LOGP(DL1IF, LOGL_DEBUG, "Data indication with raw measurements received: BER10k = %d, BTO = %d, Q = %d\n",
data_ind->ber10k, data_ind->ta_offs_qbits, data_ind->lqual_cb);
@ -824,8 +824,8 @@ static int pcu_rx_susp_req(struct gsm_pcu_if_susp_req *susp_req)
if ((ms = bts->ms_store().get_ms(susp_req->tlli))) {
/* We need to catch both pointers here since MS may become freed
after first tbf_free(dl_tbf) if only DL TBF was available */
dl_tbf = ms->dl_tbf();
ul_tbf = ms->ul_tbf();
dl_tbf = ms_dl_tbf(ms);
ul_tbf = ms_ul_tbf(ms);
if (dl_tbf)
tbf_free(dl_tbf);
if (ul_tbf)
@ -840,7 +840,7 @@ static int pcu_rx_susp_req(struct gsm_pcu_if_susp_req *susp_req)
static int pcu_rx_app_info_req(struct gsm_pcu_if_app_info_req *app_info_req)
{
LListHead<GprsMs> *ms_iter;
GprsMs *ms;
BTS *bts = BTS::main_bts();
struct gprs_rlcmac_bts *bts_data = bts->bts_data();
@ -848,9 +848,8 @@ static int pcu_rx_app_info_req(struct gsm_pcu_if_app_info_req *app_info_req)
app_info_req->application_type, app_info_req->len);
bts_data->app_info_pending = 0;
llist_for_each(ms_iter, &bts->ms_store().ms_list()) {
GprsMs *ms = ms_iter->entry();
if (!ms->dl_tbf())
llist_for_each_entry(ms, bts->ms_store().ms_list(), list) {
if (!ms_dl_tbf(ms))
continue;
bts_data->app_info_pending++;
ms->app_info_pending = true;

View File

@ -79,19 +79,13 @@ struct pcu_l1_meas_ts {
unsigned have_ms_i_level:1;
int16_t ms_i_level; /* I_LEVEL in dB */
#ifdef __cplusplus
pcu_l1_meas_ts& set_ms_i_level(int16_t v) {
ms_i_level = v; have_ms_i_level = 1; return *this;
}
pcu_l1_meas_ts() :
have_ms_i_level(0),
ms_i_level(0)
{}
#endif
};
static inline void pcu_l1_meas_ts_set_ms_i_level(struct pcu_l1_meas_ts* ts, int16_t v) {
ts->ms_i_level = v;
ts->have_ms_i_level = 1;
}
struct pcu_l1_meas {
unsigned have_rssi:1;
unsigned have_ber:1;
@ -111,48 +105,43 @@ struct pcu_l1_meas {
int16_t ms_sign_var; /* SIGN_VAR in dB */
struct pcu_l1_meas_ts ts[8];
#ifdef __cplusplus
pcu_l1_meas& set_rssi(int8_t v) { rssi = v; have_rssi = 1; return *this;}
pcu_l1_meas& set_ber(uint8_t v) { ber = v; have_ber = 1; return *this;}
pcu_l1_meas& set_bto(int16_t v) { bto = v; have_bto = 1; return *this;}
pcu_l1_meas& set_link_qual(int16_t v) {
link_qual = v; have_link_qual = 1; return *this;
}
pcu_l1_meas& set_ms_rx_qual(int16_t v) {
ms_rx_qual = v; have_ms_rx_qual = 1; return *this;
}
pcu_l1_meas& set_ms_c_value(int16_t v) {
ms_c_value = v; have_ms_c_value = 1; return *this;
}
pcu_l1_meas& set_ms_sign_var(int16_t v) {
ms_sign_var = v; have_ms_sign_var = 1; return *this;
}
pcu_l1_meas& set_ms_i_level(size_t idx, int16_t v) {
ts[idx].set_ms_i_level(v); have_ms_i_level = 1; return *this;
}
pcu_l1_meas() :
have_rssi(0),
have_ber(0),
have_bto(0),
have_link_qual(0),
have_ms_rx_qual(0),
have_ms_c_value(0),
have_ms_sign_var(0),
have_ms_i_level(0),
rssi(0),
ber(0),
bto(0),
link_qual(0),
ms_rx_qual(0),
ms_c_value(0),
ms_sign_var(0)
{}
#endif
};
static inline void pcu_l1_meas_set_rssi(struct pcu_l1_meas *m, int8_t v) {
m->rssi = v;
m->have_rssi = 1;
}
static inline void pcu_l1_meas_set_ber(struct pcu_l1_meas *m, uint8_t v) {
m->ber = v;
m->have_ber = 1;
}
static inline void pcu_l1_meas_set_bto(struct pcu_l1_meas *m, int16_t v) {
m->bto = v;
m->have_bto = 1;
}
static inline void pcu_l1_meas_set_link_qual(struct pcu_l1_meas *m, int16_t v) {
m->link_qual = v;
m->have_link_qual = 1;
}
static inline void pcu_l1_meas_set_ms_rx_qual(struct pcu_l1_meas *m, int16_t v) {
m->ms_rx_qual = v;
m->have_ms_rx_qual = 1;
}
static inline void pcu_l1_meas_set_ms_c_value(struct pcu_l1_meas *m, int16_t v) {
m->ms_c_value = v;
m->have_ms_c_value = 1;
}
static inline void pcu_l1_meas_set_ms_sign_var(struct pcu_l1_meas *m, int16_t v) {
m->ms_sign_var = v;
m->have_ms_sign_var = 1;
}
static inline void pcu_l1_meas_set_ms_i_level(struct pcu_l1_meas *m, size_t idx, int16_t v) {
pcu_l1_meas_ts_set_ms_i_level(&m->ts[idx], v);
m->have_ms_i_level = 1;
}
#ifdef __cplusplus
void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
void pcu_l1if_tx_ptcch(uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr,

View File

@ -15,26 +15,32 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/gsm/gsm_utils.h>
#ifdef __cplusplus
}
#endif
#include <time.h>
inline int msecs_to_frames(int msecs) {
static inline int msecs_to_frames(int msecs) {
return (msecs * (1024 * 1000 / 4615)) / 1024;
}
inline uint32_t next_fn(uint32_t fn, uint32_t offset)
static inline uint32_t next_fn(uint32_t fn, uint32_t offset)
{
return (fn + offset) % GSM_MAX_FN;
}
inline void csecs_to_timespec(unsigned csecs, struct timespec *ts) {
static inline void csecs_to_timespec(unsigned csecs, struct timespec *ts) {
ts->tv_sec = csecs / 100;
ts->tv_nsec = (csecs % 100) * 10000000;
}
#ifdef __cplusplus
template <typename T>
inline unsigned int pcu_bitcount(T x)
{
@ -44,8 +50,15 @@ inline unsigned int pcu_bitcount(T x)
return count;
}
#endif
inline uint8_t pcu_lsb(uint8_t x)
static inline uint8_t pcu_lsb(uint8_t x)
{
return x & -x;
}
/* Used to store a C++ class in a llist used by C code */
struct llist_item {
struct llist_head list; /* item used by llist */
void *entry;
};

View File

@ -61,7 +61,7 @@ static void tbf_print_vty_info(struct vty *vty, gprs_rlcmac_tbf *tbf)
tbf->first_ts,
tbf->first_common_ts, tbf->control_ts,
tbf->ms_class(),
tbf->ms() ? tbf->ms()->egprs_ms_class() : -1,
tbf->ms() ? ms_egprs_ms_class(tbf->ms()) : -1,
VTY_NEWLINE);
vty_out(vty, " TS_alloc=");
for (int i = 0; i < 8; i++) {
@ -79,7 +79,7 @@ static void tbf_print_vty_info(struct vty *vty, gprs_rlcmac_tbf *tbf)
ul_tbf->window_size(), win->v_q(), win->v_r());
vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, " TBF Statistics:%s", VTY_NEWLINE);
if (GPRS == tbf->ms()->mode()) {
if (GPRS == ms_mode(tbf->ms())) {
vty_out_rate_ctr_group(vty, " ", ul_tbf->m_ul_gprs_ctrs);
} else {
vty_out_rate_ctr_group(vty, " ", ul_tbf->m_ul_egprs_ctrs);
@ -92,7 +92,7 @@ static void tbf_print_vty_info(struct vty *vty, gprs_rlcmac_tbf *tbf)
win->window_stalled() ? " STALLED" : "");
vty_out(vty, "%s", VTY_NEWLINE);
vty_out_rate_ctr_group(vty, " ", tbf->m_ctrs);
if (GPRS == tbf->ms()->mode()) {
if (GPRS == ms_mode(tbf->ms())) {
vty_out_rate_ctr_group(vty, " ", dl_tbf->m_dl_gprs_ctrs);
} else {
vty_out_rate_ctr_group(vty, " ", dl_tbf->m_dl_egprs_ctrs);
@ -124,81 +124,83 @@ int pcu_vty_show_tbf_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data, uint
static int show_ms(struct vty *vty, GprsMs *ms)
{
unsigned i;
LListHead<gprs_rlcmac_tbf> *i_tbf;
struct llist_item *i_tbf;
uint8_t slots;
vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms->tlli(), ms->imsi(), VTY_NEWLINE);
vty_out(vty, " Timing advance (TA): %d%s", ms->ta(), VTY_NEWLINE);
vty_out(vty, " Coding scheme uplink: %s%s", mcs_name(ms->current_cs_ul()),
vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms_tlli(ms), ms_imsi(ms), VTY_NEWLINE);
vty_out(vty, " Timing advance (TA): %d%s", ms_ta(ms), VTY_NEWLINE);
vty_out(vty, " Coding scheme uplink: %s%s", mcs_name(ms_current_cs_ul(ms)),
VTY_NEWLINE);
vty_out(vty, " Coding scheme downlink: %s%s", mcs_name(ms->current_cs_dl()),
vty_out(vty, " Coding scheme downlink: %s%s", mcs_name(ms_current_cs_dl(ms)),
VTY_NEWLINE);
vty_out(vty, " Mode: %s%s", mode_name(ms->mode()), VTY_NEWLINE);
vty_out(vty, " MS class: %d%s", ms->ms_class(), VTY_NEWLINE);
vty_out(vty, " EGPRS MS class: %d%s", ms->egprs_ms_class(), VTY_NEWLINE);
vty_out(vty, " Mode: %s%s", mode_name(ms_mode(ms)), VTY_NEWLINE);
vty_out(vty, " MS class: %d%s", ms_ms_class(ms), VTY_NEWLINE);
vty_out(vty, " EGPRS MS class: %d%s", ms_egprs_ms_class(ms), VTY_NEWLINE);
vty_out(vty, " PACCH: ");
slots = ms->current_pacch_slots();
slots = ms_current_pacch_slots(ms);
for (int i = 0; i < 8; i++)
if (slots & (1 << i))
vty_out(vty, "%d ", i);
vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, " LLC queue length: %zd%s", ms->llc_queue()->size(),
vty_out(vty, " LLC queue length: %zd%s", llc_queue_size(ms_llc_queue(ms)),
VTY_NEWLINE);
vty_out(vty, " LLC queue octets: %zd%s", ms->llc_queue()->octets(),
vty_out(vty, " LLC queue octets: %zd%s", llc_queue_octets(ms_llc_queue(ms)),
VTY_NEWLINE);
if (ms->l1_meas()->have_rssi)
if (ms->l1_meas.have_rssi)
vty_out(vty, " RSSI: %d dBm%s",
ms->l1_meas()->rssi, VTY_NEWLINE);
if (ms->l1_meas()->have_ber)
ms->l1_meas.rssi, VTY_NEWLINE);
if (ms->l1_meas.have_ber)
vty_out(vty, " Bit error rate: %d %%%s",
ms->l1_meas()->ber, VTY_NEWLINE);
if (ms->l1_meas()->have_link_qual)
ms->l1_meas.ber, VTY_NEWLINE);
if (ms->l1_meas.have_link_qual)
vty_out(vty, " Link quality: %d dB%s",
ms->l1_meas()->link_qual, VTY_NEWLINE);
if (ms->l1_meas()->have_bto)
ms->l1_meas.link_qual, VTY_NEWLINE);
if (ms->l1_meas.have_bto)
vty_out(vty, " Burst timing offset: %d/4 bit%s",
ms->l1_meas()->bto, VTY_NEWLINE);
if (ms->l1_meas()->have_ms_rx_qual)
ms->l1_meas.bto, VTY_NEWLINE);
if (ms->l1_meas.have_ms_rx_qual)
vty_out(vty, " Downlink NACK rate: %d %%%s",
ms->nack_rate_dl(), VTY_NEWLINE);
if (ms->l1_meas()->have_ms_rx_qual)
ms_nack_rate_dl(ms), VTY_NEWLINE);
if (ms->l1_meas.have_ms_rx_qual)
vty_out(vty, " MS RX quality: %d %%%s",
ms->l1_meas()->ms_rx_qual, VTY_NEWLINE);
if (ms->l1_meas()->have_ms_c_value)
ms->l1_meas.ms_rx_qual, VTY_NEWLINE);
if (ms->l1_meas.have_ms_c_value)
vty_out(vty, " MS C value: %d dB%s",
ms->l1_meas()->ms_c_value, VTY_NEWLINE);
if (ms->l1_meas()->have_ms_sign_var)
ms->l1_meas.ms_c_value, VTY_NEWLINE);
if (ms->l1_meas.have_ms_sign_var)
vty_out(vty, " MS SIGN variance: %d dB%s",
ms->l1_meas()->ms_sign_var, VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(ms->l1_meas()->ts); ++i) {
if (ms->l1_meas()->ts[i].have_ms_i_level)
ms->l1_meas.ms_sign_var, VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(ms->l1_meas.ts); ++i) {
if (ms->l1_meas.ts[i].have_ms_i_level)
vty_out(vty, " MS I level (slot %d): %d dB%s",
i, ms->l1_meas()->ts[i].ms_i_level, VTY_NEWLINE);
i, ms->l1_meas.ts[i].ms_i_level, VTY_NEWLINE);
}
vty_out(vty, " RLC/MAC DL Control Msg: %d%s", ms->dl_ctrl_msg(),
vty_out(vty, " RLC/MAC DL Control Msg: %d%s", ms_dl_ctrl_msg(ms),
VTY_NEWLINE);
if (ms->ul_tbf())
if (ms_ul_tbf(ms))
vty_out(vty, " Uplink TBF: TFI=%d, state=%s%s",
ms->ul_tbf()->tfi(),
ms->ul_tbf()->state_name(),
ms_ul_tbf(ms)->tfi(),
ms_ul_tbf(ms)->state_name(),
VTY_NEWLINE);
if (ms->dl_tbf()) {
if (ms_dl_tbf(ms)) {
vty_out(vty, " Downlink TBF: TFI=%d, state=%s%s",
ms->dl_tbf()->tfi(),
ms->dl_tbf()->state_name(),
ms_dl_tbf(ms)->tfi(),
ms_dl_tbf(ms)->state_name(),
VTY_NEWLINE);
vty_out(vty, " Current DL Throughput: %d Kbps %s",
ms->dl_tbf()->m_bw.dl_throughput,
ms_dl_tbf(ms)->m_bw.dl_throughput,
VTY_NEWLINE);
}
llist_for_each(i_tbf, &ms->old_tbfs())
llist_for_each_entry(i_tbf, &ms->old_tbfs, list) {
struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)i_tbf->entry;
vty_out(vty, " Old %-19s TFI=%d, state=%s%s",
i_tbf->entry()->direction == GPRS_RLCMAC_UL_TBF ?
tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF ?
"Uplink TBF:" : "Downlink TBF:",
i_tbf->entry()->tfi(),
i_tbf->entry()->state_name(),
tbf->tfi(),
tbf->state_name(),
VTY_NEWLINE);
}
return CMD_SUCCESS;
}
@ -206,10 +208,10 @@ static int show_ms(struct vty *vty, GprsMs *ms)
int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
{
BTS *bts = bts_data->bts;
LListHead<GprsMs> *ms_iter;
GprsMs *ms_iter;
llist_for_each(ms_iter, &bts->ms_store().ms_list())
show_ms(vty, ms_iter->entry());
llist_for_each_entry(ms_iter, bts->ms_store().ms_list(), list)
show_ms(vty, ms_iter);
return CMD_SUCCESS;
}

View File

@ -68,9 +68,9 @@ static void get_rx_qual_meas(struct pcu_l1_meas *meas, uint8_t rx_qual_enc)
18, /* 18,10 % */
};
meas->set_ms_rx_qual(rx_qual_map[
OSMO_MIN(rx_qual_enc, ARRAY_SIZE(rx_qual_map)-1)
]);
pcu_l1_meas_set_ms_rx_qual(meas, rx_qual_map[
OSMO_MIN(rx_qual_enc, ARRAY_SIZE(rx_qual_map)-1)
]);
}
static void get_meas(struct pcu_l1_meas *meas,
@ -78,9 +78,9 @@ static void get_meas(struct pcu_l1_meas *meas,
{
unsigned i;
meas->set_ms_c_value(qr->C_VALUE);
pcu_l1_meas_set_ms_c_value(meas, qr->C_VALUE);
if (qr->Exist_SIGN_VAR)
meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
pcu_l1_meas_set_ms_sign_var(meas, (qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->I_LEVEL_TN), ARRAY_SIZE(meas->ts)); i++)
{
@ -88,7 +88,7 @@ static void get_meas(struct pcu_l1_meas *meas,
LOGP(DRLCMAC, LOGL_INFO,
"Packet resource request: i_level[%d] = %d\n",
i, qr->I_LEVEL_TN[i].I_LEVEL);
meas->set_ms_i_level(i, -2 * qr->I_LEVEL_TN[i].I_LEVEL);
pcu_l1_meas_set_ms_i_level(meas, i, -2 * qr->I_LEVEL_TN[i].I_LEVEL);
}
}
}
@ -99,8 +99,8 @@ static void get_meas(struct pcu_l1_meas *meas,
unsigned i;
get_rx_qual_meas(meas, qr->RXQUAL);
meas->set_ms_c_value(qr->C_VALUE);
meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
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 */
for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++)
{
@ -108,7 +108,7 @@ static void get_meas(struct pcu_l1_meas *meas,
LOGP(DRLCMAC, LOGL_DEBUG,
"Channel quality report: i_level[%d] = %d\n",
i, qr->Slot[i].I_LEVEL_TN);
meas->set_ms_i_level(i, -2 * qr->Slot[i].I_LEVEL_TN);
pcu_l1_meas_set_ms_i_level(meas, i, -2 * qr->Slot[i].I_LEVEL_TN);
}
}
}
@ -307,11 +307,11 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
LOGP(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->ta(),
ms->ul_tbf() ? ms->ul_tbf()->tfi() : 0,
ms->ul_tbf() ? ms->ul_tbf()->state_name() : "None",
ms->dl_tbf() ? ms->dl_tbf()->tfi() : 0,
ms->dl_tbf() ? ms->dl_tbf()->state_name() : "None");
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");
return;
}
@ -339,7 +339,7 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
tbf->n_reset(N3105);
TBF_SET_ASS_STATE_DL(tbf, GPRS_RLCMAC_DL_ASS_NONE);
new_tbf = tbf->ms() ? tbf->ms()->dl_tbf() : NULL;
new_tbf = tbf->ms() ? ms_dl_tbf(tbf->ms()) : NULL;
if (!new_tbf) {
LOGP(DRLCMAC, LOGL_ERROR, "Got ACK, but DL "
"TBF is gone TLLI=0x%08x\n", tlli);
@ -371,7 +371,7 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
tbf->n_reset(N3105);
TBF_SET_ASS_STATE_UL(tbf, GPRS_RLCMAC_UL_ASS_NONE);
new_tbf = tbf->ms() ? tbf->ms()->ul_tbf() : NULL;
new_tbf = tbf->ms() ? ms_ul_tbf(tbf->ms()) : NULL;
if (!new_tbf) {
LOGP(DRLCMAC, LOGL_ERROR, "Got ACK, but UL "
"TBF is gone TLLI=0x%08x\n", tlli);
@ -389,7 +389,7 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
/* there might be LLC packets waiting in the queue, but the DL
* TBF might have been released while the UL TBF has been
* established */
if (new_tbf->ms()->need_dl_tbf())
if (ms_need_dl_tbf(new_tbf->ms()))
new_tbf->establish_dl_tbf_on_pacch();
return;
@ -460,7 +460,7 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n
/* get measurements */
if (tbf->ms()) {
get_meas(meas, &ack_nack->Channel_Quality_Report);
tbf->ms()->update_l1_meas(meas);
ms_update_l1_meas(tbf->ms(), meas);
}
}
@ -570,19 +570,19 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
if (!ms) {
ms_found = false;
ms = bts()->ms_alloc(0, 0); /* ms class updated later */
ms->set_tlli(tlli);
ms_set_tlli(ms, tlli);
}
ul_tbf = ms->ul_tbf(); /* hence ul_tbf may be NULL */
ul_tbf = ms_ul_tbf(ms); /* hence ul_tbf may be NULL */
/* Keep the ms, even if it gets idle temporarily */
GprsMs::Guard guard(ms);
ms_ref(ms);
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "
"in packet resource request of single "
"block, so we provide one:\n");
sba = bts()->sba()->find(this, fn);
if (sba) {
ms->set_ta(sba->ta);
ms_set_ta(ms, sba->ta);
bts()->sba()->free_sba(sba);
} else if (!ul_tbf || !ul_tbf->state_is(GPRS_RLCMAC_FINISHED)) {
LOGPTBFUL(ul_tbf, LOGL_NOTICE,
@ -599,9 +599,9 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
ms_class = Decoding::get_ms_class_by_capability(&request->MS_Radio_Access_capability2);
egprs_ms_class = Decoding::get_egprs_ms_class_by_capability(&request->MS_Radio_Access_capability2);
if (ms_class)
ms->set_ms_class(ms_class);
ms_set_ms_class(ms, ms_class);
if (egprs_ms_class)
ms->set_egprs_ms_class(egprs_ms_class);
ms_set_egprs_ms_class(ms, egprs_ms_class);
}
/* Get rid of previous finished UL TBF before providing a new one */
@ -616,7 +616,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
if (!ul_tbf) {
handle_tbf_reject(bts_data(), ms, tlli,
trx_no(), ts_no);
return;
goto return_unref;
}
/* set control ts to current MS's TS, until assignment complete */
@ -630,8 +630,10 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
/* get measurements */
if (ul_tbf->ms()) {
get_meas(meas, request);
ul_tbf->ms()->update_l1_meas(meas);
ms_update_l1_meas(ul_tbf->ms(), meas);
}
return_unref:
ms_unref(ms);
return;
}
@ -674,10 +676,10 @@ void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *repor
LOGP(DRLCMAC, LOGL_NOTICE, "MS send measurement "
"but TLLI 0x%08x is unknown\n", report->TLLI);
ms = bts()->ms_alloc(0, 0);
ms->set_tlli(report->TLLI);
ms_set_tlli(ms, report->TLLI);
}
if ((sba = bts()->sba()->find(this, fn))) {
ms->set_ta(sba->ta);
ms_set_ta(ms, sba->ta);
bts()->sba()->free_sba(sba);
}
gprs_rlcmac_meas_rep(ms, report);

View File

@ -141,14 +141,13 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(BTS *bts_, GprsMs *ms, gprs_rlcmac_tbf_directio
m_tfi(0),
m_created_ts(0),
m_ctrs(NULL),
m_ms(ms),
state(GPRS_RLCMAC_NULL),
m_ms(ms),
dl_ass_state(GPRS_RLCMAC_DL_ASS_NONE),
ul_ass_state(GPRS_RLCMAC_UL_ASS_NONE),
ul_ack_state(GPRS_RLCMAC_UL_ACK_NONE),
poll_state(GPRS_RLCMAC_POLL_NONE),
m_list(this),
m_ms_list(this),
m_egprs_enabled(false)
{
/* The classes of these members do not have proper constructors yet.
@ -158,6 +157,9 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(BTS *bts_, GprsMs *ms, gprs_rlcmac_tbf_directio
memset(&Narr, 0, sizeof(Narr));
memset(&gsm_timer, 0, sizeof(gsm_timer));
memset(&m_ms_list, 0, sizeof(m_ms_list));
m_ms_list.entry = this;
m_rlc.init();
m_llc.init();
@ -171,27 +173,27 @@ gprs_rlcmac_bts *gprs_rlcmac_tbf::bts_data() const
uint32_t gprs_rlcmac_tbf::tlli() const
{
return m_ms ? m_ms->tlli() : GSM_RESERVED_TMSI;
return m_ms ? ms_tlli(m_ms) : GSM_RESERVED_TMSI;
}
const char *gprs_rlcmac_tbf::imsi() const
{
return m_ms->imsi();
return ms_imsi(m_ms);
}
uint8_t gprs_rlcmac_tbf::ta() const
{
return m_ms->ta();
return ms_ta(m_ms);
}
void gprs_rlcmac_tbf::set_ta(uint8_t ta)
{
ms()->set_ta(ta);
ms_set_ta(m_ms, ta);
}
uint8_t gprs_rlcmac_tbf::ms_class() const
{
return m_ms->ms_class();
return ms_ms_class(m_ms);
}
enum CodingScheme gprs_rlcmac_tbf::current_cs() const
@ -199,28 +201,21 @@ enum CodingScheme gprs_rlcmac_tbf::current_cs() const
enum CodingScheme cs;
if (direction == GPRS_RLCMAC_UL_TBF)
cs = m_ms ? m_ms->current_cs_ul() : UNKNOWN;
cs = m_ms ? ms_current_cs_ul(m_ms) : UNKNOWN;
else
cs = m_ms ? m_ms->current_cs_dl() : UNKNOWN;
cs = m_ms ? ms_current_cs_dl(m_ms) : UNKNOWN;
return cs;
}
gprs_llc_queue *gprs_rlcmac_tbf::llc_queue()
{
return m_ms ? m_ms->llc_queue() : NULL;
return m_ms ? ms_llc_queue(m_ms) : NULL;
}
const gprs_llc_queue *gprs_rlcmac_tbf::llc_queue() const
{
return m_ms ? m_ms->llc_queue() : NULL;
}
size_t gprs_rlcmac_tbf::llc_queue_size() const
{
/* m_ms->llc_queue() never returns NULL: GprsMs::m_llc_queue is a
* member instance. */
return m_ms ? m_ms->llc_queue()->size() : 0;
return ms_llc_queue(m_ms);
}
void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
@ -229,13 +224,13 @@ void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
return;
if (m_ms) {
m_ms->detach_tbf(this);
ms_detach_tbf(m_ms, this);
}
m_ms = ms;
if (m_ms)
m_ms->attach_tbf(this);
ms_attach_tbf(m_ms, this);
}
void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
@ -247,18 +242,18 @@ void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction di
* 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
* IMSI in gprs_rlcmac_dl_tbf::handle() so there should be a unified solution */
if (!ms()->check_tlli(tlli)) {
if (!ms_check_tlli(ms(), tlli)) {
GprsMs *old_ms;
old_ms = bts->ms_store().get_ms(tlli, 0, NULL);
if (old_ms)
ms()->merge_and_clear_ms(old_ms);
ms_merge_and_clear_ms(ms(), old_ms);
}
if (dir == GPRS_RLCMAC_UL_TBF)
ms()->set_tlli(tlli);
ms_set_tlli(ms(), tlli);
else
ms()->confirm_tlli(tlli);
ms_confirm_tlli(ms(), tlli);
}
static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
@ -745,7 +740,7 @@ int gprs_rlcmac_tbf::setup(int8_t use_trx, bool single_slot)
struct gprs_rlcmac_bts *bts_data = bts->bts_data();
int rc;
if (m_ms->mode() != GPRS)
if (ms_mode(m_ms) != GPRS)
enable_egprs();
m_created_ts = time(NULL);
@ -775,7 +770,7 @@ int gprs_rlcmac_tbf::setup(int8_t use_trx, bool single_slot)
return -1;
}
m_ms->attach_tbf(this);
ms_attach_tbf(m_ms, this);
return 0;
}
@ -895,7 +890,7 @@ struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts)
}
if (ms())
new_dl_tbf = ms()->dl_tbf();
new_dl_tbf = ms_dl_tbf(ms());
if (!new_dl_tbf) {
LOGPTBFDL(this, LOGL_ERROR,
@ -1012,7 +1007,7 @@ struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn, uint8_t ts)
return NULL;
if (ms())
new_tbf = ms()->ul_tbf();
new_tbf = ms_ul_tbf(ms());
if (!new_tbf) {
LOGPTBFUL(this, LOGL_ERROR,
"We have a schedule for uplink assignment, but there is no uplink TBF\n");
@ -1170,3 +1165,58 @@ bool gprs_rlcmac_tbf::is_control_ts(uint8_t ts) const
{
return ts == control_ts;
}
/* 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;
}
struct GprsMs *tbf_ms(struct gprs_rlcmac_tbf *tbf)
{
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();
}

View File

@ -25,11 +25,21 @@
#include "llc.h"
#include "rlc.h"
#include "cxx_linuxlist.h"
#include "pcu_utils.h"
#include <gprs_debug.h>
#include <gsm_timer.h>
#include <stdint.h>
struct bssgp_bvc_ctx;
struct gprs_rlcmac_bts;
#endif
struct GprsMs;
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/utils.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/logging.h>
@ -37,12 +47,8 @@ extern "C" {
#include <osmocom/gsm/gsm48.h>
#include "coding_scheme.h"
#ifdef __cplusplus
}
struct bssgp_bvc_ctx;
class GprsMs;
struct gprs_rlcmac_bts;
#endif
/*
@ -181,6 +187,28 @@ enum tbf_counters { /* TBF counters from 3GPP TS 44.060 §13.4 */
#define TBF_ASS_TYPE_SET(t, kind) do { t->ass_type_mod(kind, false, __FILE__, __LINE__); } while(0)
#define TBF_ASS_TYPE_UNSET(t, kind) do { t->ass_type_mod(kind, true, __FILE__, __LINE__); } while(0)
#ifdef __cplusplus
extern "C" {
#endif
struct gprs_rlcmac_tbf;
const char *tbf_name(struct gprs_rlcmac_tbf *tbf);
enum gprs_rlcmac_tbf_state tbf_state(const struct gprs_rlcmac_tbf *tbf);
enum gprs_rlcmac_tbf_direction tbf_direction(const struct gprs_rlcmac_tbf *tbf);
void tbf_set_ms(struct gprs_rlcmac_tbf *tbf, struct GprsMs *ms);
struct llist_head *tbf_ms_list(struct gprs_rlcmac_tbf *tbf);
struct GprsMs *tbf_ms(struct gprs_rlcmac_tbf *tbf);
bool tbf_timers_pending(struct gprs_rlcmac_tbf *tbf, enum tbf_timers t);
void tbf_free(struct gprs_rlcmac_tbf *tbf);
struct gprs_llc *tbf_llc(struct gprs_rlcmac_tbf *tbf);
uint8_t tbf_first_common_ts(const struct gprs_rlcmac_tbf *tbf);
uint8_t tbf_dl_slots(const struct gprs_rlcmac_tbf *tbf);
uint8_t tbf_ul_slots(const struct gprs_rlcmac_tbf *tbf);
bool tbf_is_tfi_assigned(const struct gprs_rlcmac_tbf *tbf);
int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
struct gprs_rlcmac_tbf {
@ -255,7 +283,6 @@ struct gprs_rlcmac_tbf {
void set_ta(uint8_t);
uint8_t ms_class() const;
enum CodingScheme current_cs() const;
size_t llc_queue_size() const;
time_t created_ts() const;
uint8_t dl_slots() const;
@ -269,9 +296,6 @@ struct gprs_rlcmac_tbf {
/* attempt to make things a bit more fair */
void rotate_in_list();
LListHead<gprs_rlcmac_tbf>& ms_list() {return this->m_ms_list;}
const LListHead<gprs_rlcmac_tbf>& ms_list() const {return this->m_ms_list;}
LListHead<gprs_rlcmac_tbf>& list();
const LListHead<gprs_rlcmac_tbf>& list() const;
@ -321,6 +345,8 @@ struct gprs_rlcmac_tbf {
time_t m_created_ts;
struct rate_ctr_group *m_ctrs;
enum gprs_rlcmac_tbf_state state;
struct llist_item m_ms_list;
protected:
gprs_rlcmac_bts *bts_data() const;
@ -331,26 +357,20 @@ protected:
static const char *tbf_state_name[6];
class GprsMs *m_ms;
struct GprsMs *m_ms;
private:
void enable_egprs();
enum gprs_rlcmac_tbf_state state;
enum gprs_rlcmac_tbf_dl_ass_state dl_ass_state;
enum gprs_rlcmac_tbf_ul_ass_state ul_ass_state;
enum gprs_rlcmac_tbf_ul_ack_state ul_ack_state;
enum gprs_rlcmac_tbf_poll_state poll_state;
LListHead<gprs_rlcmac_tbf> m_list;
LListHead<gprs_rlcmac_tbf> m_ms_list;
bool m_egprs_enabled;
struct osmo_timer_list Tarr[T_MAX];
uint8_t Narr[N_MAX];
mutable char m_name_buf[60];
};
void tbf_free(struct gprs_rlcmac_tbf *tbf);
int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf);
inline bool gprs_rlcmac_tbf::state_is(enum gprs_rlcmac_tbf_state rhs) const
{
return state == rhs;
@ -381,8 +401,6 @@ inline bool gprs_rlcmac_tbf::state_is_not(enum gprs_rlcmac_tbf_state rhs) const
return state != rhs;
}
const char *tbf_name(gprs_rlcmac_tbf *tbf);
inline const char *gprs_rlcmac_tbf::state_name() const
{
return tbf_state_name[state];

View File

@ -131,7 +131,7 @@ struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts, GprsMs
LOGP(DTBF, LOGL_DEBUG, "********** DL-TBF starts here **********\n");
LOGP(DTBF, LOGL_INFO, "Allocating DL TBF: MS_CLASS=%d/%d\n",
ms->ms_class(), ms->egprs_ms_class());
ms_ms_class(ms), ms_egprs_ms_class(ms));
tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
@ -241,7 +241,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts, GprsMs *ms,
struct gprs_rlcmac_ul_tbf *ul_tbf = NULL, *old_ul_tbf;
struct gprs_rlcmac_dl_tbf *dl_tbf = NULL;
ul_tbf = ms->ul_tbf();
ul_tbf = ms_ul_tbf(ms);
if (ul_tbf && ul_tbf->m_contention_resolution_done
&& !ul_tbf->m_final_ack_sent) {
@ -291,41 +291,43 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
/* check for existing TBF */
ms = bts->bts->ms_store().get_ms(tlli, tlli_old, imsi);
if (ms && strlen(ms->imsi()) == 0) {
if (ms && strlen(ms_imsi(ms)) == 0) {
ms_old = bts->bts->ms_store().get_ms(0, 0, imsi);
if (ms_old && ms_old != ms) {
/* The TLLI has changed (RAU), so there are two MS
* objects for the same MS */
LOGP(DTBF, LOGL_NOTICE,
"There is a new MS object for the same MS: (0x%08x, '%s') -> (0x%08x, '%s')\n",
ms_old->tlli(), ms_old->imsi(), ms->tlli(), ms->imsi());
ms_tlli(ms_old), ms_imsi(ms_old), ms_tlli(ms), ms_imsi(ms));
GprsMs::Guard guard_old(ms_old);
ms_ref(ms_old);
if (!ms->dl_tbf() && ms_old->dl_tbf()) {
if (!ms_dl_tbf(ms) && ms_dl_tbf(ms_old)) {
LOGP(DTBF, LOGL_NOTICE,
"IMSI %s, old TBF %s: moving DL TBF to new MS object\n",
imsi, ms_old->dl_tbf()->name());
dl_tbf = ms_old->dl_tbf();
imsi, ms_dl_tbf(ms_old)->name());
dl_tbf = ms_dl_tbf(ms_old);
/* Move the DL TBF to the new MS */
dl_tbf->set_ms(ms);
}
ms->merge_and_clear_ms(ms_old);
ms_merge_and_clear_ms(ms, ms_old);
ms_unref(ms_old);
}
}
if (!ms)
ms = bts->bts->ms_alloc(ms_class, egprs_ms_class);
ms->set_imsi(imsi);
ms->confirm_tlli(tlli);
if (!ms->ms_class() && ms_class) {
ms->set_ms_class(ms_class);
ms_set_imsi(ms, imsi);
ms_confirm_tlli(ms, tlli);
if (!ms_ms_class(ms) && ms_class) {
ms_set_ms_class(ms, ms_class);
}
if (!ms->egprs_ms_class() && egprs_ms_class) {
ms->set_egprs_ms_class(egprs_ms_class);
if (!ms_egprs_ms_class(ms) && egprs_ms_class) {
ms_set_egprs_ms_class(ms, egprs_ms_class);
}
dl_tbf = ms->dl_tbf();
dl_tbf = ms_dl_tbf(ms);
if (!dl_tbf) {
rc = tbf_new_dl_assignment(bts, ms, &dl_tbf);
if (rc < 0)
@ -344,7 +346,7 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
uint32_t octets = 0, frames = 0;
struct timespec hyst_delta = {0, 0};
const unsigned keep_small_thresh = 60;
const gprs_llc_queue::MetaInfo *info;
const MetaInfo *info;
if (bts_data()->llc_discard_csec)
csecs_to_timespec(bts_data()->llc_discard_csec, &hyst_delta);
@ -358,9 +360,9 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
gprs_bssgp_update_queue_delay(tv_recv, &tv_now);
if (ms() && ms()->codel_state()) {
int bytes = llc_queue()->octets();
if (gprs_codel_control(ms()->codel_state(),
if (ms() && ms_codel_state(ms())) {
int bytes = llc_queue_octets(llc_queue());
if (gprs_codel_control(ms_codel_state(ms()),
tv_recv, &tv_now, bytes))
goto drop_frame;
}
@ -402,7 +404,7 @@ drop_frame:
LOGPTBFDL(this, LOGL_NOTICE, "Discarding LLC PDU "
"because lifetime limit reached, "
"count=%u new_queue_size=%zu\n",
frames, llc_queue_size());
frames, llc_queue_size(llc_queue()));
if (frames > 0xff)
frames = 0xff;
if (octets > 0xffffff)
@ -459,7 +461,7 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
} else if (bsn < 0 && is_egprs_enabled() && req_mcs_kind == EGPRS_GMSK) {
/* New data to be sent for EGPRS TBF but we are required to downgrade to
* MCS1-4, because USF for GPRS-only MS will be sent */
force_cs = m_ms->current_cs_dl();
force_cs = ms_current_cs_dl(m_ms);
if (force_cs > MCS4) {
force_cs = bts->cs_dl_is_supported(MCS4) ? MCS4 :
bts->cs_dl_is_supported(MCS3) ? MCS3 :
@ -467,7 +469,7 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
MCS1;
LOGPTBFDL(this, LOGL_DEBUG,
"Force downgrading DL %s -> %s due to USF for GPRS-only MS\n",
mcs_name(m_ms->current_cs_dl()), mcs_name(force_cs));
mcs_name(ms_current_cs_dl(m_ms)), mcs_name(force_cs));
}
}
@ -483,14 +485,14 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
if (is_egprs_enabled()) {
/* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */
m_rlc.block(bsn)->cs_current_trans = get_retx_mcs(m_rlc.block(bsn)->cs_init,
ms()->current_cs_dl(),
ms_current_cs_dl(ms()),
!bts->bts_data()->dl_arq_type);
LOGPTBFDL(this, LOGL_DEBUG,
"initial_cs_dl(%s) last_mcs(%s) demanded_mcs(%s) cs_trans(%s) arq_type(%d) bsn(%d)\n",
mcs_name(m_rlc.block(bsn)->cs_init),
mcs_name(m_rlc.block(bsn)->cs_last),
mcs_name(ms()->current_cs_dl()),
mcs_name(ms_current_cs_dl(ms())),
mcs_name(m_rlc.block(bsn)->cs_current_trans),
bts->bts_data()->dl_arq_type, bsn);
@ -635,7 +637,7 @@ void gprs_rlcmac_dl_tbf::schedule_next_frame()
{
struct msgb *msg;
if (m_llc.frame_length() != 0)
if (llc_frame_length(&m_llc) != 0)
return;
/* dequeue next LLC frame, if any */
@ -661,7 +663,7 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, enum CodingScheme cs)
int write_offset = 0;
Encoding::AppendResult ar;
if (m_llc.frame_length() == 0)
if (llc_frame_length(&m_llc) == 0)
schedule_next_frame();
OSMO_ASSERT(mcs_is_valid(cs));
@ -693,7 +695,7 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, enum CodingScheme cs)
bool is_final;
int payload_written = 0;
if (m_llc.frame_length() == 0) {
if (llc_frame_length(&m_llc) == 0) {
/* It is not clear, when the next real data will
* arrive, so request a DL ack/nack now */
request_dl_ack();
@ -731,10 +733,10 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, enum CodingScheme cs)
LOGPTBFDL(this, LOGL_DEBUG,
"Empty chunk, added LLC dummy command of size %d, drained_since=%d\n",
m_llc.frame_length(), frames_since_last_drain(fn));
llc_frame_length(&m_llc), frames_since_last_drain(fn));
}
is_final = llc_queue_size() == 0 && !keep_open(fn);
is_final = llc_queue_size(llc_queue()) == 0 && !keep_open(fn);
ar = Encoding::rlc_data_to_dl_append(rdbi, cs,
&m_llc, &write_offset, &num_chunks, data, is_final, &payload_written);
@ -745,9 +747,9 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, enum CodingScheme cs)
if (ar == Encoding::AR_NEED_MORE_BLOCKS)
break;
LOGPTBFDL(this, LOGL_DEBUG, "Complete DL frame, len=%d\n", m_llc.frame_length());
gprs_rlcmac_dl_bw(this, m_llc.frame_length());
bts->do_rate_ctr_add(CTR_LLC_DL_BYTES, m_llc.frame_length());
LOGPTBFDL(this, LOGL_DEBUG, "Complete DL frame, len=%d\n", llc_frame_length(&m_llc));
gprs_rlcmac_dl_bw(this, llc_frame_length(&m_llc));
bts->do_rate_ctr_add(CTR_LLC_DL_BYTES, llc_frame_length(&m_llc));
m_llc.reset();
if (is_final) {
@ -1131,7 +1133,7 @@ int gprs_rlcmac_dl_tbf::update_window(unsigned first_bsn,
error_rate = analyse_errors(show_rbb, behind_last_bsn, &ana_res);
if (bts_data()->cs_adj_enabled && ms())
ms()->update_error_rate(this, error_rate);
ms_update_error_rate(ms(), this, error_rate);
m_window.update(bts, rbb, first_bsn, &lost, &received);
rate_ctr_add(&m_ctrs->ctr[TBF_CTR_RLC_NACKED], lost);
@ -1186,7 +1188,7 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
error_rate = analyse_errors(show_rbb, ssn, &ana_res);
if (bts_data()->cs_adj_enabled && ms())
ms()->update_error_rate(this, error_rate);
ms_update_error_rate(ms(), this, error_rate);
m_window.update(bts, show_rbb, ssn,
&lost, &received);
@ -1221,7 +1223,7 @@ int gprs_rlcmac_dl_tbf::maybe_start_new_window()
release();
/* check for LLC PDU in the LLC Queue */
if (llc_queue_size() > 0)
if (llc_queue_size(llc_queue()) > 0)
/* we have more data so we will re-use this tbf */
establish_dl_tbf_on_pacch();
@ -1331,8 +1333,8 @@ bool gprs_rlcmac_dl_tbf::need_control_ts() const
bool gprs_rlcmac_dl_tbf::have_data() const
{
return m_llc.chunk_size() > 0 ||
(llc_queue_size() > 0);
return llc_chunk_size(&m_llc) > 0 ||
(llc_queue_size(llc_queue()) > 0);
}
static inline int frames_since_last(int32_t last, unsigned fn)
@ -1556,3 +1558,11 @@ void gprs_rlcmac_dl_tbf::update_coding_scheme_counter_dl(enum CodingScheme cs)
mcs_name(cs));
}
}
struct gprs_rlcmac_dl_tbf *as_dl_tbf(struct gprs_rlcmac_tbf *tbf)
{
if (tbf && tbf->direction == GPRS_RLCMAC_DL_TBF)
return static_cast<gprs_rlcmac_dl_tbf *>(tbf);
else
return NULL;
}

View File

@ -141,15 +141,17 @@ inline uint16_t gprs_rlcmac_dl_tbf::window_size() const
return m_window.ws();
}
inline gprs_rlcmac_dl_tbf *as_dl_tbf(gprs_rlcmac_tbf *tbf)
{
if (tbf && tbf->direction == GPRS_RLCMAC_DL_TBF)
return static_cast<gprs_rlcmac_dl_tbf *>(tbf);
else
return NULL;
}
struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts, GprsMs *ms,
int8_t use_trx, bool single_slot);
#else /* ifdef __cplusplus */
struct gprs_rlcmac_dl_tbf;
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct gprs_rlcmac_dl_tbf *as_dl_tbf(struct gprs_rlcmac_tbf *tbf);
#ifdef __cplusplus
}
#endif

View File

@ -105,7 +105,7 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts, GprsMs
LOGP(DTBF, LOGL_DEBUG, "********** UL-TBF starts here **********\n");
LOGP(DTBF, LOGL_INFO, "Allocating UL TBF: MS_CLASS=%d/%d\n",
ms->ms_class(), ms->egprs_ms_class());
ms_ms_class(ms), ms_egprs_ms_class(ms));
tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
if (!tbf)
@ -172,7 +172,7 @@ struct gprs_rlcmac_ul_tbf *handle_tbf_reject(struct gprs_rlcmac_bts *bts,
if (!ms)
ms = bts->bts->ms_alloc(0, 0);
ms->set_tlli(tlli);
ms_set_tlli(ms, tlli);
ul_tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
if (!ul_tbf)
@ -185,7 +185,7 @@ struct gprs_rlcmac_ul_tbf *handle_tbf_reject(struct gprs_rlcmac_bts *bts,
ul_tbf->bts->do_rate_ctr_inc(CTR_TBF_UL_ALLOCATED);
TBF_SET_ASS_ON(ul_tbf, GPRS_RLCMAC_FLAG_PACCH, false);
ms->attach_tbf(ul_tbf);
ms_attach_tbf(ms, ul_tbf);
ul_tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);
TBF_SET_ASS_STATE_UL(ul_tbf, GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ);
ul_tbf->control_ts = ts;
@ -252,14 +252,14 @@ int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
frame->is_complete);
m_llc.append_frame(data + frame->offset, frame->length);
m_llc.consume(frame->length);
llc_consume(&m_llc, frame->length);
}
if (frame->is_complete) {
/* send frame to SGSN */
LOGPTBFUL(this, LOGL_DEBUG, "complete UL frame len=%d\n", m_llc.frame_length());
LOGPTBFUL(this, LOGL_DEBUG, "complete UL frame len=%d\n", llc_frame_length(&m_llc));
snd_ul_ud();
bts->do_rate_ctr_add(CTR_LLC_UL_BYTES, m_llc.frame_length());
bts->do_rate_ctr_add(CTR_LLC_UL_BYTES, llc_frame_length(&m_llc));
m_llc.reset();
}
}
@ -357,7 +357,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
/* store measurement values */
if (ms())
ms()->update_l1_meas(meas);
ms_update_l1_meas(ms(), meas);
uint32_t new_tlli = GSM_RESERVED_TMSI;
unsigned int block_idx;
@ -559,10 +559,10 @@ int gprs_rlcmac_ul_tbf::snd_ul_ud()
{
uint8_t qos_profile[3];
struct msgb *llc_pdu;
unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + m_llc.frame_length();
unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + llc_frame_length(&m_llc);
struct bssgp_bvc_ctx *bctx = gprs_bssgp_pcu_current_bctx();
LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] %s len=%d\n", tbf_name(this), m_llc.frame_length());
LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] %s len=%d\n", tbf_name(this), llc_frame_length(&m_llc));
if (!bctx) {
LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
m_llc.reset_frame_space();
@ -570,8 +570,8 @@ int gprs_rlcmac_ul_tbf::snd_ul_ud()
}
llc_pdu = msgb_alloc_headroom(msg_len, msg_len,"llc_pdu");
uint8_t *buf = msgb_push(llc_pdu, TL16V_GROSS_LEN(sizeof(uint8_t)*m_llc.frame_length()));
tl16v_put(buf, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*m_llc.frame_length(), m_llc.frame);
uint8_t *buf = msgb_push(llc_pdu, TL16V_GROSS_LEN(sizeof(uint8_t)*llc_frame_length(&m_llc)));
tl16v_put(buf, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*llc_frame_length(&m_llc), m_llc.frame);
qos_profile[0] = QOS_PROFILE >> 16;
qos_profile[1] = QOS_PROFILE >> 8;
qos_profile[2] = QOS_PROFILE;
@ -772,3 +772,11 @@ gprs_rlc_window *gprs_rlcmac_ul_tbf::window()
{
return &m_window;
}
struct gprs_rlcmac_ul_tbf *as_ul_tbf(struct gprs_rlcmac_tbf *tbf)
{
if (tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
return static_cast<gprs_rlcmac_ul_tbf *>(tbf);
else
return NULL;
}

View File

@ -108,32 +108,28 @@ protected:
gprs_rlc_ul_window m_window;
};
#ifdef __cplusplus
extern "C" {
#endif
void update_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, int8_t ta_delta);
void set_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, uint8_t ta);
#ifdef __cplusplus
}
#endif
inline uint16_t gprs_rlcmac_ul_tbf::window_size() const
{
return m_window.ws();
}
inline gprs_rlcmac_ul_tbf *as_ul_tbf(gprs_rlcmac_tbf *tbf)
{
if (tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
return static_cast<gprs_rlcmac_ul_tbf *>(tbf);
else
return NULL;
}
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts, GprsMs *ms, int8_t use_trx, bool single_slot);
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts, GprsMs *ms,
int8_t use_trx, uint32_t tlli);
struct gprs_rlcmac_ul_tbf *handle_tbf_reject(struct gprs_rlcmac_bts *bts,
GprsMs *ms, uint32_t tlli, uint8_t trx_no, uint8_t ts_no);
#else /* ifdef __cplusplus */
struct gprs_rlcmac_ul_tbf;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void update_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, int8_t ta_delta);
void set_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, uint8_t ta);
struct gprs_rlcmac_ul_tbf *as_ul_tbf(struct gprs_rlcmac_tbf *tbf);
#ifdef __cplusplus
}
#endif

View File

@ -224,12 +224,12 @@ static inline bool test_alloc_b_ul_dl(bool ts0, bool ts1, bool ts2, bool ts3, bo
return false;
OSMO_ASSERT(ul_tbf->ms());
OSMO_ASSERT(ul_tbf->ms()->current_trx());
OSMO_ASSERT(ms_current_trx(ul_tbf->ms()));
dump_assignment(ul_tbf, "UL", verbose);
/* assume final ack has not been sent */
dl_tbf = tbf_alloc_dl_tbf(bts, ms, ms->current_trx()->trx_no, false);
dl_tbf = tbf_alloc_dl_tbf(bts, ms, ms_current_trx(ms)->trx_no, false);
if (!dl_tbf)
return false;
@ -268,11 +268,11 @@ static inline bool test_alloc_b_dl_ul(bool ts0, bool ts1, bool ts2, bool ts3, bo
dl_tbf->update_ms(0x23, GPRS_RLCMAC_DL_TBF);
OSMO_ASSERT(dl_tbf->ms() == ms);
OSMO_ASSERT(dl_tbf->ms()->current_trx());
OSMO_ASSERT(ms_current_trx(dl_tbf->ms()));
dump_assignment(dl_tbf, "DL", verbose);
ul_tbf = tbf_alloc_ul_tbf(bts, ms, ms->current_trx()->trx_no, false);
ul_tbf = tbf_alloc_ul_tbf(bts, ms, ms_current_trx(ms)->trx_no, false);
if (!ul_tbf)
return false;
@ -319,8 +319,8 @@ static inline bool test_alloc_b_jolly(uint8_t ms_class)
return false;
OSMO_ASSERT(ul_tbf->ms() == ms);
OSMO_ASSERT(ul_tbf->ms()->current_trx());
trx_no = ms->current_trx()->trx_no;
OSMO_ASSERT(ms_current_trx(ul_tbf->ms()));
trx_no = ms_current_trx(ms)->trx_no;
dump_assignment(ul_tbf, "UL", true);
/* assume final ack has not been sent */
@ -453,50 +453,55 @@ static inline char *test_mode_descr(enum test_mode t)
}
}
static GprsMs *alloc_tbfs(BTS *the_bts, GprsMs *ms, enum test_mode mode)
static GprsMs *alloc_tbfs(BTS *the_bts, struct GprsMs *old_ms, enum test_mode mode)
{
struct gprs_rlcmac_bts *bts;
struct GprsMs *ms, *new_ms;
uint8_t trx_no = -1;
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(old_ms != NULL);
bts = the_bts->bts_data();
gprs_rlcmac_tbf *tbf = NULL;
if (ms && ms->current_trx())
trx_no = ms->current_trx()->trx_no;
if (ms_current_trx(old_ms))
trx_no = ms_current_trx(old_ms)->trx_no;
GprsMs::Guard guard1(ms);
ms_ref(old_ms);
/* Allocate what is needed first */
switch (mode) {
case TEST_MODE_UL_ONLY:
case TEST_MODE_DL_AFTER_UL:
case TEST_MODE_UL_AND_DL:
if (ms->ul_tbf())
tbf_free(ms->ul_tbf());
tbf = tbf_alloc_ul_tbf(bts, ms, trx_no, false);
if (tbf == NULL)
if (ms_ul_tbf(old_ms))
tbf_free(ms_ul_tbf(old_ms));
tbf = tbf_alloc_ul_tbf(bts, old_ms, trx_no, false);
if (tbf == NULL) {
ms_unref(old_ms);
return NULL;
}
break;
case TEST_MODE_DL_ONLY:
case TEST_MODE_UL_AFTER_DL:
case TEST_MODE_DL_AND_UL:
if (ms->dl_tbf())
tbf_free(ms->dl_tbf());
tbf = tbf_alloc_dl_tbf(bts, ms, trx_no, false);
if (tbf == NULL)
if (ms_dl_tbf(old_ms))
tbf_free(ms_dl_tbf(old_ms));
tbf = tbf_alloc_dl_tbf(bts, old_ms, trx_no, false);
if (tbf == NULL) {
ms_unref(old_ms);
return NULL;
}
}
OSMO_ASSERT(tbf);
OSMO_ASSERT(tbf->ms());
OSMO_ASSERT(ms == NULL || ms == tbf->ms());
OSMO_ASSERT(old_ms == tbf->ms());
ms = tbf->ms();
GprsMs::Guard guard2(ms);
ms_ref(ms);
new_ms = ms;
/* Continue with what is needed next */
switch (mode) {
case TEST_MODE_UL_ONLY:
@ -506,12 +511,12 @@ static GprsMs *alloc_tbfs(BTS *the_bts, GprsMs *ms, enum test_mode mode)
case TEST_MODE_DL_AFTER_UL:
case TEST_MODE_UL_AND_DL:
ms = alloc_tbfs(the_bts, ms, TEST_MODE_DL_ONLY);
new_ms = alloc_tbfs(the_bts, ms, TEST_MODE_DL_ONLY);
break;
case TEST_MODE_UL_AFTER_DL:
case TEST_MODE_DL_AND_UL:
ms = alloc_tbfs(the_bts, ms, TEST_MODE_UL_ONLY);
new_ms = alloc_tbfs(the_bts, ms, TEST_MODE_UL_ONLY);
break;
}
@ -527,10 +532,12 @@ static GprsMs *alloc_tbfs(BTS *the_bts, GprsMs *ms, enum test_mode mode)
break;
}
if (!ms && tbf)
if (!new_ms && tbf)
tbf_free(tbf);
return guard2.is_idle() ? NULL : ms;
ms_unref(old_ms);
ms_unref(ms);
return new_ms;
}
static unsigned alloc_many_tbfs(BTS *the_bts, unsigned min_class,
@ -556,16 +563,16 @@ static unsigned alloc_many_tbfs(BTS *the_bts, unsigned min_class,
ms = the_bts->ms_by_tlli(tlli);
if (!ms)
ms = the_bts->ms_alloc(0, 0);
ms->set_ms_class(ms_class);
ms_set_ms_class(ms, ms_class);
ms = alloc_tbfs(the_bts, ms, mode);
if (!ms)
break;
ms->set_tlli(tlli);
ms_set_tlli(ms, tlli);
ul_tbf = ms->ul_tbf();
dl_tbf = ms->dl_tbf();
trx = ms->current_trx();
ul_tbf = ms_ul_tbf(ms);
dl_tbf = ms_dl_tbf(ms);
trx = ms_current_trx(ms);
OSMO_ASSERT(ul_tbf || dl_tbf);
@ -616,12 +623,12 @@ static unsigned alloc_many_tbfs(BTS *the_bts, unsigned min_class,
get_dir_char(0x80, ul_slots, dl_slots, busy_slots));
if (tfi >= 0) {
OSMO_ASSERT(ms->current_trx());
OSMO_ASSERT(ms_current_trx(ms));
tfi2 = the_bts->tfi_find_free(dir, &trx_no2,
ms->current_trx()->trx_no);
ms_current_trx(ms)->trx_no);
OSMO_ASSERT(tfi != tfi2);
OSMO_ASSERT(tfi2 < 0 ||
trx_no2 == ms->current_trx()->trx_no);
trx_no2 == ms_current_trx(ms)->trx_no);
}
ms_class += 1;

View File

@ -152,9 +152,9 @@ void cleanup()
{
fprintf(stderr, "--- %s ---\n", __func__);
tbf_free(tbf1);
tbf_free(tbf2);
BTS::main_bts()->cleanup();
talloc_free(tbf1);
talloc_free(tbf2);
/* FIXME: talloc report disabled, because bts->ms_alloc() in prepare_bts_with_two_dl_tbf_subscr() causes leak */
/* talloc_report_full(tall_pcu_ctx, stderr); */
talloc_free(tall_pcu_ctx);

View File

@ -52,3 +52,14 @@ Previous Packet Application Information was not sent to all subscribers, overwri
Sending Packet Application Information to 2 subscribers with active TBF
--- cleanup ---
PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 1 TBFs, USFs = 00, TFIs = 00000002.
PDCH(TS 5, TRX 0): Detaching TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 1 TBFs, USFs = 00, TFIs = 00000002.
PDCH(TS 6, TRX 0): Detaching TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 1 TBFs, USFs = 00, TFIs = 00000002.
PDCH(TS 7, TRX 0): Detaching TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000.
Detaching TBF from MS object, TLLI = 0xffffffff, TBF = TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS)
PDCH(TS 4, TRX 0): Detaching TBF(TFI=1 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000.
PDCH(TS 5, TRX 0): Detaching TBF(TFI=1 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000.
PDCH(TS 6, TRX 0): Detaching TBF(TFI=1 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000.
Detaching TBF from MS object, TLLI = 0xffffffff, TBF = TBF(TFI=1 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS)
Destroying MS object, TLLI = 0xffffffff
Destroying MS object, TLLI = 0xffffffff

View File

@ -619,7 +619,7 @@ static void test_rlc_unit_encoder()
write_offset = 0;
memset(data, 0, sizeof(data));
OSMO_ASSERT(llc.chunk_size() == 1);
OSMO_ASSERT(llc_chunk_size(&llc) == 1);
count_payload = -1;
@ -767,7 +767,7 @@ static void test_rlc_unit_encoder()
write_offset = 0;
memset(data, 0, sizeof(data));
OSMO_ASSERT(llc.chunk_size() == 10);
OSMO_ASSERT(llc_chunk_size(&llc) == 10);
count_payload = -1;
ar = Encoding::rlc_data_to_dl_append(&rdbi, cs,
@ -899,7 +899,7 @@ static void test_rlc_unit_encoder()
write_offset = 0;
memset(data, 0, sizeof(data));
OSMO_ASSERT(llc.chunk_size() == 0);
OSMO_ASSERT(llc_chunk_size(&llc) == 0);
count_payload = -1;
ar = Encoding::rlc_data_to_dl_append(&rdbi, cs,
@ -1167,7 +1167,6 @@ static void uplink_header_type_2_parsing_test(BTS *the_bts,
uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta,
uint8_t ms_class)
{
struct pcu_l1_meas meas;
int tfi = 0;
uint8_t data[79] = {0};
struct gprs_rlc_ul_header_egprs_2 *egprs2 = NULL;

View File

@ -60,10 +60,10 @@ static void enqueue_data(gprs_llc_queue *queue, const uint8_t *data, size_t len,
}
static void dequeue_and_check(gprs_llc_queue *queue, const uint8_t *exp_data,
size_t len, const gprs_llc_queue::MetaInfo *exp_info)
size_t len, const MetaInfo *exp_info)
{
struct msgb *llc_msg;
const gprs_llc_queue::MetaInfo *info_res;
const MetaInfo *info_res;
llc_msg = queue->dequeue(&info_res);
OSMO_ASSERT(llc_msg != NULL);
@ -88,7 +88,7 @@ static void enqueue_data(gprs_llc_queue *queue, const char *message,
}
static void dequeue_and_check(gprs_llc_queue *queue, const char *exp_message,
const gprs_llc_queue::MetaInfo *exp_info = 0)
const MetaInfo *exp_info = 0)
{
dequeue_and_check(queue,
(uint8_t *)(exp_message), strlen(exp_message), exp_info);
@ -101,33 +101,33 @@ static void test_llc_queue()
printf("=== start %s ===\n", __func__);
queue.init();
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
llc_queue_init(&queue);
OSMO_ASSERT(llc_queue_size(&queue) == 0);
OSMO_ASSERT(llc_queue_octets(&queue) == 0);
enqueue_data(&queue, "LLC message", &expire_time);
OSMO_ASSERT(queue.size() == 1);
OSMO_ASSERT(queue.octets() == 11);
OSMO_ASSERT(llc_queue_size(&queue) == 1);
OSMO_ASSERT(llc_queue_octets(&queue) == 11);
enqueue_data(&queue, "other LLC message", &expire_time);
OSMO_ASSERT(queue.size() == 2);
OSMO_ASSERT(queue.octets() == 28);
OSMO_ASSERT(llc_queue_size(&queue) == 2);
OSMO_ASSERT(llc_queue_octets(&queue) == 28);
dequeue_and_check(&queue, "LLC message");
OSMO_ASSERT(queue.size() == 1);
OSMO_ASSERT(queue.octets() == 17);
OSMO_ASSERT(llc_queue_size(&queue) == 1);
OSMO_ASSERT(llc_queue_octets(&queue) == 17);
dequeue_and_check(&queue, "other LLC message");
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
OSMO_ASSERT(llc_queue_size(&queue) == 0);
OSMO_ASSERT(llc_queue_octets(&queue) == 0);
enqueue_data(&queue, "LLC", &expire_time);
OSMO_ASSERT(queue.size() == 1);
OSMO_ASSERT(queue.octets() == 3);
OSMO_ASSERT(llc_queue_size(&queue) == 1);
OSMO_ASSERT(llc_queue_octets(&queue) == 3);
queue.clear(NULL);
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
llc_queue_clear(&queue, NULL);
OSMO_ASSERT(llc_queue_size(&queue) == 0);
OSMO_ASSERT(llc_queue_octets(&queue) == 0);
printf("=== end %s ===\n", __func__);
}
@ -135,14 +135,14 @@ static void test_llc_queue()
static void test_llc_meta()
{
gprs_llc_queue queue;
gprs_llc_queue::MetaInfo info1 = {0};
gprs_llc_queue::MetaInfo info2 = {0};
MetaInfo info1 = {0};
MetaInfo info2 = {0};
printf("=== start %s ===\n", __func__);
queue.init();
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
llc_queue_init(&queue);
OSMO_ASSERT(llc_queue_size(&queue) == 0);
OSMO_ASSERT(llc_queue_octets(&queue) == 0);
info1.recv_time.tv_sec = 123456777;
info1.recv_time.tv_nsec = 123456000;
@ -161,9 +161,9 @@ static void test_llc_meta()
dequeue_and_check(&queue, "LLC message 1", &info1);
dequeue_and_check(&queue, "LLC message 2", &info2);
queue.clear(NULL);
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
llc_queue_clear(&queue, NULL);
OSMO_ASSERT(llc_queue_size(&queue) == 0);
OSMO_ASSERT(llc_queue_octets(&queue) == 0);
printf("=== end %s ===\n", __func__);
}
@ -176,8 +176,8 @@ static void test_llc_merge()
printf("=== start %s ===\n", __func__);
queue1.init();
queue2.init();
llc_queue_init(&queue1);
llc_queue_init(&queue2);
clk_mono_override_time->tv_sec += 1;
enqueue_data(&queue1, "*A*", &expire_time);
@ -194,17 +194,17 @@ static void test_llc_merge()
clk_mono_override_time->tv_sec += 1;
enqueue_data(&queue2, "*E*", &expire_time);
OSMO_ASSERT(queue1.size() == 3);
OSMO_ASSERT(queue1.octets() == 9);
OSMO_ASSERT(queue2.size() == 2);
OSMO_ASSERT(queue2.octets() == 6);
OSMO_ASSERT(llc_queue_size(&queue1) == 3);
OSMO_ASSERT(llc_queue_octets(&queue1) == 9);
OSMO_ASSERT(llc_queue_size(&queue2) == 2);
OSMO_ASSERT(llc_queue_octets(&queue2) == 6);
queue2.move_and_merge(&queue1);
llc_queue_move_and_merge(&queue2, &queue1);
OSMO_ASSERT(queue1.size() == 0);
OSMO_ASSERT(queue1.octets() == 0);
OSMO_ASSERT(queue2.size() == 5);
OSMO_ASSERT(queue2.octets() == 15);
OSMO_ASSERT(llc_queue_size(&queue1) == 0);
OSMO_ASSERT(llc_queue_octets(&queue1) == 0);
OSMO_ASSERT(llc_queue_size(&queue2) == 5);
OSMO_ASSERT(llc_queue_octets(&queue2) == 15);
dequeue_and_check(&queue2, "*A*");
dequeue_and_check(&queue2, "*B*");
@ -212,8 +212,8 @@ static void test_llc_merge()
dequeue_and_check(&queue2, "*D*");
dequeue_and_check(&queue2, "*E*");
OSMO_ASSERT(queue2.size() == 0);
OSMO_ASSERT(queue2.octets() == 0);
OSMO_ASSERT(llc_queue_size(&queue2) == 0);
OSMO_ASSERT(llc_queue_octets(&queue2) == 0);
printf("=== end %s ===\n", __func__);
}

View File

@ -56,33 +56,33 @@ static void test_ms_state()
printf("=== start %s ===\n", __func__);
ms = new GprsMs(&the_bts, tlli);
OSMO_ASSERT(ms->is_idle());
ms = ms_alloc(&the_bts, tlli);
OSMO_ASSERT(ms_is_idle(ms));
dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms);
ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);
ms->attach_tbf(ul_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms->dl_tbf() == NULL);
ms_attach_tbf(ms, ul_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
OSMO_ASSERT(ms_dl_tbf(ms) == NULL);
ms->attach_tbf(dl_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf);
ms_attach_tbf(ms, dl_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);
OSMO_ASSERT(ms->tbf(GPRS_RLCMAC_UL_TBF) == ul_tbf);
OSMO_ASSERT(ms->tbf(GPRS_RLCMAC_DL_TBF) == dl_tbf);
OSMO_ASSERT(ms_tbf(ms, GPRS_RLCMAC_UL_TBF) == ul_tbf);
OSMO_ASSERT(ms_tbf(ms, GPRS_RLCMAC_DL_TBF) == dl_tbf);
ms->detach_tbf(ul_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == NULL);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf);
ms_detach_tbf(ms, ul_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);
ms->detach_tbf(dl_tbf);
ms_detach_tbf(ms, dl_tbf);
/* The ms object is freed now */
ms = NULL;
@ -92,6 +92,23 @@ static void test_ms_state()
printf("=== end %s ===\n", __func__);
}
static enum {CB_UNKNOWN, CB_IS_IDLE, CB_IS_ACTIVE} last_cb = CB_UNKNOWN;
static void ms_idle_cb(struct GprsMs *ms)
{
OSMO_ASSERT(ms_is_idle(ms));
printf(" ms_idle() was called\n");
last_cb = CB_IS_IDLE;
}
static void ms_active_cb(struct GprsMs *ms)
{
OSMO_ASSERT(!ms_is_idle(ms));
printf(" ms_active() was called\n");
last_cb = CB_IS_ACTIVE;
}
static struct gpr_ms_callback ms_cb = {
.ms_idle = ms_idle_cb,
.ms_active = ms_active_cb
};
static void test_ms_callback()
{
uint32_t tlli = 0xffeeddbb;
@ -99,63 +116,50 @@ static void test_ms_callback()
gprs_rlcmac_ul_tbf *ul_tbf;
BTS the_bts;
GprsMs *ms;
static enum {UNKNOWN, IS_IDLE, IS_ACTIVE} last_cb = UNKNOWN;
struct MyCallback: public GprsMs::Callback {
virtual void ms_idle(class GprsMs *ms) {
OSMO_ASSERT(ms->is_idle());
printf(" ms_idle() was called\n");
last_cb = IS_IDLE;
}
virtual void ms_active(class GprsMs *ms) {
OSMO_ASSERT(!ms->is_idle());
printf(" ms_active() was called\n");
last_cb = IS_ACTIVE;
}
} cb;
last_cb = CB_UNKNOWN;
printf("=== start %s ===\n", __func__);
ms = new GprsMs(&the_bts, tlli);
ms->set_callback(&cb);
ms = ms_alloc(&the_bts, tlli);
ms_set_callback(ms, &ms_cb);
OSMO_ASSERT(ms->is_idle());
OSMO_ASSERT(ms_is_idle(ms));
dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms);
ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);
OSMO_ASSERT(last_cb == UNKNOWN);
OSMO_ASSERT(last_cb == CB_UNKNOWN);
ms->attach_tbf(ul_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms->dl_tbf() == NULL);
OSMO_ASSERT(last_cb == IS_ACTIVE);
ms_attach_tbf(ms, ul_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
OSMO_ASSERT(ms_dl_tbf(ms) == NULL);
OSMO_ASSERT(last_cb == CB_IS_ACTIVE);
last_cb = UNKNOWN;
last_cb = CB_UNKNOWN;
ms->attach_tbf(dl_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf);
OSMO_ASSERT(last_cb == UNKNOWN);
ms_attach_tbf(ms, dl_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);
OSMO_ASSERT(last_cb == CB_UNKNOWN);
ms->detach_tbf(ul_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == NULL);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf);
OSMO_ASSERT(last_cb == UNKNOWN);
ms_detach_tbf(ms, ul_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);
OSMO_ASSERT(last_cb == CB_UNKNOWN);
ms->detach_tbf(dl_tbf);
OSMO_ASSERT(ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == NULL);
OSMO_ASSERT(ms->dl_tbf() == NULL);
OSMO_ASSERT(last_cb == IS_IDLE);
ms_detach_tbf(ms, dl_tbf);
OSMO_ASSERT(ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == NULL);
OSMO_ASSERT(last_cb == CB_IS_IDLE);
last_cb = UNKNOWN;
delete ms;
last_cb = CB_UNKNOWN;
talloc_free(ms);
talloc_free(dl_tbf);
talloc_free(ul_tbf);
@ -163,6 +167,22 @@ static void test_ms_callback()
printf("=== end %s ===\n", __func__);
}
static bool was_idle;
static void ms_replace_tbf_idle_cb(struct GprsMs *ms)
{
OSMO_ASSERT(ms_is_idle(ms));
printf(" ms_idle() was called\n");
was_idle = true;
}
static void ms_replace_tbf_active_cb(struct GprsMs *ms)
{
OSMO_ASSERT(!ms_is_idle(ms));
printf(" ms_active() was called\n");
}
static struct gpr_ms_callback ms_replace_tbf_cb = {
.ms_idle = ms_replace_tbf_idle_cb,
.ms_active = ms_replace_tbf_active_cb
};
static void test_ms_replace_tbf()
{
uint32_t tlli = 0xffeeddbb;
@ -170,26 +190,13 @@ static void test_ms_replace_tbf()
gprs_rlcmac_ul_tbf *ul_tbf;
BTS the_bts;
GprsMs *ms;
static bool was_idle;
struct MyCallback: public GprsMs::Callback {
virtual void ms_idle(class GprsMs *ms) {
OSMO_ASSERT(ms->is_idle());
printf(" ms_idle() was called\n");
was_idle = true;
}
virtual void ms_active(class GprsMs *ms) {
OSMO_ASSERT(!ms->is_idle());
printf(" ms_active() was called\n");
}
} cb;
printf("=== start %s ===\n", __func__);
ms = new GprsMs(&the_bts, tlli);
ms->set_callback(&cb);
ms = ms_alloc(&the_bts, tlli);
ms_set_callback(ms, &ms_replace_tbf_cb);
OSMO_ASSERT(ms->is_idle());
OSMO_ASSERT(ms_is_idle(ms));
was_idle = false;
dl_tbf[0] = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
@ -199,49 +206,49 @@ static void test_ms_replace_tbf()
ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);
ms->attach_tbf(dl_tbf[0]);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == NULL);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf[0]);
OSMO_ASSERT(llist_empty(&ms->old_tbfs()));
ms_attach_tbf(ms, dl_tbf[0]);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[0]);
OSMO_ASSERT(llist_empty(&ms->old_tbfs));
OSMO_ASSERT(!was_idle);
ms->attach_tbf(dl_tbf[1]);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == NULL);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]);
OSMO_ASSERT(!llist_empty(&ms->old_tbfs()));
ms_attach_tbf(ms, dl_tbf[1]);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[1]);
OSMO_ASSERT(!llist_empty(&ms->old_tbfs));
OSMO_ASSERT(!was_idle);
ms->attach_tbf(ul_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]);
OSMO_ASSERT(!llist_empty(&ms->old_tbfs()));
ms_attach_tbf(ms, ul_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[1]);
OSMO_ASSERT(!llist_empty(&ms->old_tbfs));
OSMO_ASSERT(!was_idle);
ms->detach_tbf(ul_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == NULL);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]);
OSMO_ASSERT(!llist_empty(&ms->old_tbfs()));
ms_detach_tbf(ms, ul_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[1]);
OSMO_ASSERT(!llist_empty(&ms->old_tbfs));
OSMO_ASSERT(!was_idle);
ms->detach_tbf(dl_tbf[0]);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == NULL);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]);
OSMO_ASSERT(llist_empty(&ms->old_tbfs()));
ms_detach_tbf(ms, dl_tbf[0]);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[1]);
OSMO_ASSERT(llist_empty(&ms->old_tbfs));
OSMO_ASSERT(!was_idle);
ms->detach_tbf(dl_tbf[1]);
OSMO_ASSERT(ms->is_idle());
OSMO_ASSERT(ms->ul_tbf() == NULL);
OSMO_ASSERT(ms->dl_tbf() == NULL);
OSMO_ASSERT(llist_empty(&ms->old_tbfs()));
ms_detach_tbf(ms, dl_tbf[1]);
OSMO_ASSERT(ms_is_idle(ms));
OSMO_ASSERT(ms_ul_tbf(ms) == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == NULL);
OSMO_ASSERT(llist_empty(&ms->old_tbfs));
OSMO_ASSERT(was_idle);
delete ms;
talloc_free(ms);
talloc_free(dl_tbf[0]);
talloc_free(dl_tbf[1]);
@ -260,86 +267,86 @@ static void test_ms_change_tlli()
printf("=== start %s ===\n", __func__);
ms = new GprsMs(&the_bts, start_tlli);
ms = ms_alloc(&the_bts, start_tlli);
OSMO_ASSERT(ms->is_idle());
OSMO_ASSERT(ms_is_idle(ms));
/* MS announces TLLI, SGSN uses it immediately */
ms->set_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(ms->check_tlli(start_tlli));
ms_set_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(ms_check_tlli(ms, start_tlli));
ms->confirm_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(!ms->check_tlli(start_tlli));
ms_confirm_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(!ms_check_tlli(ms, start_tlli));
/* MS announces TLLI, SGSN uses it later */
ms->set_tlli(start_tlli);
ms->confirm_tlli(start_tlli);
ms_set_tlli(ms, start_tlli);
ms_confirm_tlli(ms, start_tlli);
ms->set_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(ms->check_tlli(start_tlli));
ms_set_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(ms_check_tlli(ms, start_tlli));
ms->confirm_tlli(start_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(ms->check_tlli(start_tlli));
ms_confirm_tlli(ms, start_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(ms_check_tlli(ms, start_tlli));
ms->set_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(ms->check_tlli(start_tlli));
ms_set_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(ms_check_tlli(ms, start_tlli));
ms->confirm_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(!ms->check_tlli(start_tlli));
ms_confirm_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(!ms_check_tlli(ms, start_tlli));
/* MS announces TLLI, SGSN uses it later after another new TLLI */
ms->set_tlli(start_tlli);
ms->confirm_tlli(start_tlli);
ms_set_tlli(ms, start_tlli);
ms_confirm_tlli(ms, start_tlli);
ms->set_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(ms->check_tlli(start_tlli));
ms_set_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(ms_check_tlli(ms, start_tlli));
ms->confirm_tlli(other_sgsn_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(ms->check_tlli(other_sgsn_tlli));
ms_confirm_tlli(ms, other_sgsn_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(ms_check_tlli(ms, other_sgsn_tlli));
ms->set_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(ms->check_tlli(other_sgsn_tlli));
ms_set_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(ms_check_tlli(ms, other_sgsn_tlli));
ms->confirm_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(!ms->check_tlli(start_tlli));
OSMO_ASSERT(!ms->check_tlli(other_sgsn_tlli));
ms_confirm_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(!ms_check_tlli(ms, start_tlli));
OSMO_ASSERT(!ms_check_tlli(ms, other_sgsn_tlli));
/* SGSN uses the new TLLI before it is announced by the MS (shouldn't
* happen in normal use) */
ms->set_tlli(start_tlli);
ms->confirm_tlli(start_tlli);
ms_set_tlli(ms, start_tlli);
ms_confirm_tlli(ms, start_tlli);
ms->confirm_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == start_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(ms->check_tlli(start_tlli));
ms_confirm_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == start_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(ms_check_tlli(ms, start_tlli));
ms->set_tlli(new_ms_tlli);
OSMO_ASSERT(ms->tlli() == new_ms_tlli);
OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
OSMO_ASSERT(!ms->check_tlli(start_tlli));
ms_set_tlli(ms, new_ms_tlli);
OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);
OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));
OSMO_ASSERT(!ms_check_tlli(ms, start_tlli));
delete ms;
talloc_free(ms);
printf("=== end %s ===\n", __func__);
}
@ -353,9 +360,9 @@ static GprsMs *prepare_ms(GprsMsStorage *st, uint32_t tlli, enum gprs_rlcmac_tbf
ms = st->create_ms();
if (dir == GPRS_RLCMAC_UL_TBF)
ms->set_tlli(tlli);
ms_set_tlli(ms, tlli);
else
ms->confirm_tlli(tlli);
ms_confirm_tlli(ms, tlli);
return ms;
}
@ -378,44 +385,44 @@ static void test_ms_storage()
ms = prepare_ms(&store, tlli + 0, GPRS_RLCMAC_UL_TBF);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->tlli() == tlli + 0);
ms->set_imsi(imsi1);
OSMO_ASSERT(strcmp(ms->imsi(), imsi1) == 0);
OSMO_ASSERT(ms_tlli(ms) == tlli + 0);
ms_set_imsi(ms, imsi1);
OSMO_ASSERT(strcmp(ms_imsi(ms), imsi1) == 0);
ms_tmp = store.get_ms(tlli + 0);
OSMO_ASSERT(ms == ms_tmp);
OSMO_ASSERT(ms->tlli() == tlli + 0);
OSMO_ASSERT(ms_tlli(ms) == tlli + 0);
ms_tmp = store.get_ms(0, 0, imsi1);
OSMO_ASSERT(ms == ms_tmp);
OSMO_ASSERT(strcmp(ms->imsi(), imsi1) == 0);
OSMO_ASSERT(strcmp(ms_imsi(ms), imsi1) == 0);
ms_tmp = store.get_ms(0, 0, imsi2);
OSMO_ASSERT(ms_tmp == NULL);
ms = prepare_ms(&store, tlli + 1, GPRS_RLCMAC_UL_TBF);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->tlli() == tlli + 1);
ms->set_imsi(imsi2);
OSMO_ASSERT(strcmp(ms->imsi(), imsi2) == 0);
OSMO_ASSERT(ms_tlli(ms) == tlli + 1);
ms_set_imsi(ms, imsi2);
OSMO_ASSERT(strcmp(ms_imsi(ms), imsi2) == 0);
ms_tmp = store.get_ms(tlli + 1);
OSMO_ASSERT(ms == ms_tmp);
OSMO_ASSERT(ms->tlli() == tlli + 1);
OSMO_ASSERT(ms_tlli(ms) == tlli + 1);
ms_tmp = store.get_ms(0, 0, imsi1);
OSMO_ASSERT(ms_tmp != NULL);
OSMO_ASSERT(ms_tmp != ms);
ms_tmp = store.get_ms(0, 0, imsi2);
OSMO_ASSERT(ms == ms_tmp);
OSMO_ASSERT(strcmp(ms->imsi(), imsi2) == 0);
OSMO_ASSERT(strcmp(ms_imsi(ms), imsi2) == 0);
/* delete ms */
ms = store.get_ms(tlli + 0);
OSMO_ASSERT(ms != NULL);
ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);
ms->attach_tbf(ul_tbf);
ms->detach_tbf(ul_tbf);
ms_attach_tbf(ms, ul_tbf);
ms_detach_tbf(ms, ul_tbf);
ms = store.get_ms(tlli + 0);
OSMO_ASSERT(ms == NULL);
ms = store.get_ms(tlli + 1);
@ -424,8 +431,8 @@ static void test_ms_storage()
/* delete ms */
ms = store.get_ms(tlli + 1);
OSMO_ASSERT(ms != NULL);
ms->attach_tbf(ul_tbf);
ms->detach_tbf(ul_tbf);
ms_attach_tbf(ms, ul_tbf);
ms_detach_tbf(ms, ul_tbf);
ms = store.get_ms(tlli + 1);
OSMO_ASSERT(ms == NULL);
@ -441,62 +448,49 @@ static void test_ms_timeout()
gprs_rlcmac_ul_tbf *ul_tbf;
BTS the_bts;
GprsMs *ms;
static enum {UNKNOWN, IS_IDLE, IS_ACTIVE} last_cb = UNKNOWN;
struct MyCallback: public GprsMs::Callback {
virtual void ms_idle(class GprsMs *ms) {
OSMO_ASSERT(ms->is_idle());
printf(" ms_idle() was called\n");
last_cb = IS_IDLE;
}
virtual void ms_active(class GprsMs *ms) {
OSMO_ASSERT(!ms->is_idle());
printf(" ms_active() was called\n");
last_cb = IS_ACTIVE;
}
} cb;
last_cb = CB_UNKNOWN;
printf("=== start %s ===\n", __func__);
ms = new GprsMs(&the_bts, tlli);
ms->set_callback(&cb);
ms->set_timeout(1);
ms = ms_alloc(&the_bts, tlli);
ms_set_callback(ms, &ms_cb);
ms_set_timeout(ms, 1);
OSMO_ASSERT(ms->is_idle());
OSMO_ASSERT(ms_is_idle(ms));
dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms);
ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);
OSMO_ASSERT(last_cb == UNKNOWN);
OSMO_ASSERT(last_cb == CB_UNKNOWN);
ms->attach_tbf(ul_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(last_cb == IS_ACTIVE);
ms_attach_tbf(ms, ul_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(last_cb == CB_IS_ACTIVE);
last_cb = UNKNOWN;
last_cb = CB_UNKNOWN;
ms->attach_tbf(dl_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(last_cb == UNKNOWN);
ms_attach_tbf(ms, dl_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(last_cb == CB_UNKNOWN);
ms->detach_tbf(ul_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(last_cb == UNKNOWN);
ms_detach_tbf(ms, ul_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(last_cb == CB_UNKNOWN);
ms->detach_tbf(dl_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(last_cb == UNKNOWN);
ms_detach_tbf(ms, dl_tbf);
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(last_cb == CB_UNKNOWN);
usleep(1100000);
osmo_timers_update();
OSMO_ASSERT(ms->is_idle());
OSMO_ASSERT(last_cb == IS_IDLE);
OSMO_ASSERT(ms_is_idle(ms));
OSMO_ASSERT(last_cb == CB_IS_IDLE);
last_cb = UNKNOWN;
delete ms;
last_cb = CB_UNKNOWN;
talloc_free(ms);
talloc_free(dl_tbf);
talloc_free(ul_tbf);
@ -519,21 +513,21 @@ static void test_ms_cs_selection()
bts->cs_downgrade_threshold = 0;
bts->cs_adj_lower_limit = 0;
ms = new GprsMs(&the_bts, tlli);
ms = ms_alloc(&the_bts, tlli);
OSMO_ASSERT(ms->is_idle());
OSMO_ASSERT(ms_is_idle(ms));
dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms);
ms->attach_tbf(dl_tbf);
ms_attach_tbf(ms, dl_tbf);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(!ms_is_idle(ms));
OSMO_ASSERT(mcs_chan_code(ms->current_cs_dl()) == 3);
OSMO_ASSERT(mcs_chan_code(ms_current_cs_dl(ms)) == 3);
bts->cs_downgrade_threshold = 200;
OSMO_ASSERT(mcs_chan_code(ms->current_cs_dl()) == 2);
OSMO_ASSERT(mcs_chan_code(ms_current_cs_dl(ms)) == 2);
talloc_free(dl_tbf);
@ -543,10 +537,10 @@ static void test_ms_cs_selection()
static void dump_ms(const GprsMs *ms, const char *pref)
{
printf("%s MS DL %s/%s, UL %s/%s, mode %s, <%s>\n", pref,
mcs_name(ms->current_cs_dl()), mcs_name(ms->max_cs_dl()),
mcs_name(ms->current_cs_ul()), mcs_name(ms->max_cs_ul()),
mode_name(ms->mode()),
ms->is_idle() ? "IDLE" : "ACTIVE");
mcs_name(ms_current_cs_dl(ms)), mcs_name(ms_max_cs_dl(ms)),
mcs_name(ms_current_cs_ul(ms)), mcs_name(ms_max_cs_ul(ms)),
mode_name(ms_mode(ms)),
ms_is_idle(ms) ? "IDLE" : "ACTIVE");
}
static void test_ms_mcs_mode()
@ -560,48 +554,48 @@ static void test_ms_mcs_mode()
printf("=== start %s ===\n", __func__);
ms1 = new GprsMs(&the_bts, tlli);
ms1 = ms_alloc(&the_bts, tlli);
dump_ms(ms1, "1: no BTS defaults ");
bts->initial_cs_dl = 4;
bts->initial_cs_ul = 1;
bts->cs_downgrade_threshold = 0;
ms2 = new GprsMs(&the_bts, tlli + 1);
ms2 = ms_alloc(&the_bts, tlli + 1);
dump_ms(ms2, "2: with BTS defaults");
dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms2);
ms2->attach_tbf(dl_tbf);
ms_attach_tbf(ms2, dl_tbf);
dump_ms(ms2, "2: after TBF attach ");
ms1->set_mode(EGPRS);
ms_set_mode(ms1, EGPRS);
dump_ms(ms1, "1: after mode set ");
ms2->set_mode(EGPRS);
ms_set_mode(ms2, EGPRS);
dump_ms(ms2, "2: after mode set ");
ms1->set_current_cs_dl(MCS7);
ms_set_current_cs_dl(ms1, MCS7);
dump_ms(ms1, "1: after MCS set ");
ms2->set_current_cs_dl(MCS8);
ms_set_current_cs_dl(ms2, MCS8);
dump_ms(ms2, "2: after MCS set ");
ms1->set_mode(EGPRS_GMSK);
ms_set_mode(ms1, EGPRS_GMSK);
dump_ms(ms1, "1: after mode set ");
ms2->set_mode(EGPRS_GMSK);
ms_set_mode(ms2, EGPRS_GMSK);
dump_ms(ms2, "2: after mode set ");
// FIXME: following code triggers ASAN failure:
// ms2->detach_tbf(dl_tbf);
// dump_ms(ms2, "2: after TBF detach ");
ms1->set_mode(GPRS);
ms_set_mode(ms1, GPRS);
dump_ms(ms1, "1: after mode set ");
ms2->set_mode(GPRS);
ms_set_mode(ms2, GPRS);
dump_ms(ms2, "2: after mode set ");
talloc_free(dl_tbf);

View File

@ -109,14 +109,14 @@ static void test_tbf_tlli_update()
OSMO_ASSERT(dl_tbf != NULL);
dl_tbf->update_ms(0x2342, GPRS_RLCMAC_DL_TBF);
dl_tbf->set_ta(4);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);
OSMO_ASSERT(dl_tbf->ms() == ms);
gprs_rlcmac_tbf *ul_tbf = tbf_alloc_ul_tbf(the_bts.bts_data(),
ms, 0, false);
OSMO_ASSERT(ul_tbf != NULL);
ul_tbf->update_ms(0x2342, GPRS_RLCMAC_UL_TBF);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
OSMO_ASSERT(ul_tbf->ms() == ms);
OSMO_ASSERT(the_bts.ms_by_tlli(0x2342) == ms);
@ -133,8 +133,8 @@ static void test_tbf_tlli_update()
ms_new = the_bts.ms_by_tlli(0x4232);
OSMO_ASSERT(ms == ms_new);
OSMO_ASSERT(ms->dl_tbf() == dl_tbf);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
/* Now use the new TLLI for UL */
ul_tbf->update_ms(0x4232, GPRS_RLCMAC_UL_TBF);
@ -143,7 +143,7 @@ static void test_tbf_tlli_update()
ms_new = the_bts.ms_by_tlli(0x4232);
OSMO_ASSERT(ms_new != NULL);
OSMO_ASSERT(ms_new->ta() == 4);
OSMO_ASSERT(ms_ta(ms_new) == 4);
OSMO_ASSERT(ul_tbf->ta() == 4);
OSMO_ASSERT(dl_tbf->ta() == 4);
@ -298,25 +298,27 @@ static void test_tbf_final_ack(enum test_tbf_final_ack_mode test_mode)
/* Clean up and ensure tbfs are in the correct state */
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE));
new_tbf = ms->dl_tbf();
new_tbf = ms_dl_tbf(ms);
check_tbf(new_tbf);
OSMO_ASSERT(new_tbf != dl_tbf);
OSMO_ASSERT(new_tbf->tfi() == 1);
check_tbf(dl_tbf);
TBF_SET_ASS_STATE_DL(dl_tbf, GPRS_RLCMAC_DL_ASS_NONE);
if (test_mode == TEST_MODE_REVERSE_FREE) {
GprsMs::Guard guard(ms);
ms_ref(ms);
tbf_free(new_tbf);
OSMO_ASSERT(ms->dl_tbf() == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == NULL);
check_tbf(dl_tbf);
tbf_free(dl_tbf);
ms_unref(ms);
} else {
GprsMs::Guard guard(ms);
ms_ref(ms);
tbf_free(dl_tbf);
OSMO_ASSERT(ms->dl_tbf() == new_tbf);
OSMO_ASSERT(ms_dl_tbf(ms) == new_tbf);
check_tbf(new_tbf);
tbf_free(new_tbf);
OSMO_ASSERT(ms->dl_tbf() == NULL);
OSMO_ASSERT(ms_dl_tbf(ms) == NULL);
ms_unref(ms);
}
fprintf(stderr, "=== end %s ===\n", __func__);
@ -421,32 +423,33 @@ static void test_tbf_imsi()
dl_tbf[0]->update_ms(0xf1000001, GPRS_RLCMAC_DL_TBF);
dl_tbf[1]->update_ms(0xf1000002, GPRS_RLCMAC_DL_TBF);
dl_tbf[0]->ms()->set_imsi("001001000000001");
ms_set_imsi(dl_tbf[0]->ms(), "001001000000001");
ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000001");
OSMO_ASSERT(ms1 != NULL);
ms2 = the_bts.ms_store().get_ms(0xf1000001);
OSMO_ASSERT(ms2 != NULL);
OSMO_ASSERT(strcmp(ms2->imsi(), "001001000000001") == 0);
OSMO_ASSERT(strcmp(ms_imsi(ms2), "001001000000001") == 0);
OSMO_ASSERT(ms1 == ms2);
/* change the IMSI on TBF 0 */
dl_tbf[0]->ms()->set_imsi("001001000000002");
ms_set_imsi(dl_tbf[0]->ms(), "001001000000002");
ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000001");
OSMO_ASSERT(ms1 == NULL);
ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000002");
OSMO_ASSERT(ms1 != NULL);
OSMO_ASSERT(strcmp(ms2->imsi(), "001001000000002") == 0);
OSMO_ASSERT(strcmp(ms_imsi(ms2), "001001000000002") == 0);
OSMO_ASSERT(ms1 == ms2);
/* use the same IMSI on TBF 1 */
{
GprsMs::Guard guard(ms2);
dl_tbf[1]->ms()->set_imsi("001001000000002");
ms_ref(ms2);
ms_set_imsi(dl_tbf[1]->ms(), "001001000000002");
ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000002");
OSMO_ASSERT(ms1 != NULL);
OSMO_ASSERT(ms1 != ms2);
OSMO_ASSERT(strcmp(ms1->imsi(), "001001000000002") == 0);
OSMO_ASSERT(strcmp(ms2->imsi(), "") == 0);
OSMO_ASSERT(strcmp(ms_imsi(ms1), "001001000000002") == 0);
OSMO_ASSERT(strcmp(ms_imsi(ms2), "") == 0);
ms_unref(ms2);
}
ms2 = the_bts.ms_store().get_ms(0xf1000001);
@ -539,8 +542,8 @@ static void test_tbf_dl_llc_loss()
ms = the_bts.ms_store().get_ms(0, 0, imsi);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->dl_tbf() != NULL);
ms->dl_tbf()->set_ta(0);
OSMO_ASSERT(ms_dl_tbf(ms) != NULL);
ms_dl_tbf(ms)->set_ta(0);
/* Handle LLC frame 2 */
memset(buf, 2, sizeof(buf));
@ -549,7 +552,7 @@ static void test_tbf_dl_llc_loss()
OSMO_ASSERT(rc >= 0);
/* TBF establishment fails (timeout) */
tbf_free(ms->dl_tbf());
tbf_free(ms_dl_tbf(ms));
/* Handle LLC frame 3 */
memset(buf, 3, sizeof(buf));
@ -557,7 +560,7 @@ static void test_tbf_dl_llc_loss()
delay_csec, buf, sizeof(buf));
OSMO_ASSERT(rc >= 0);
OSMO_ASSERT(ms->dl_tbf() != NULL);
OSMO_ASSERT(ms_dl_tbf(ms) != NULL);
/* Get first BSN */
struct msgb *msg;
@ -572,8 +575,8 @@ static void test_tbf_dl_llc_loss()
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 },
};
while (ms->dl_tbf()->have_data()) {
msg = ms->dl_tbf()->create_dl_acked_block(fn += 4, 7);
while (ms_dl_tbf(ms)->have_data()) {
msg = ms_dl_tbf(ms)->create_dl_acked_block(fn += 4, 7);
fprintf(stderr, "MSG = %s\n", msgb_hexdump(msg));
if (!msgb_eq_data_print(msg, exp[expected_data - 1], GSM_MACBLOCK_LEN))
fprintf(stderr, "%s failed at %u\n", __func__, expected_data);
@ -742,8 +745,8 @@ static gprs_rlcmac_ul_tbf *puan_urbb_len_issue(BTS *the_bts,
ms = the_bts->ms_by_tlli(tlli);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->ta() == qta/4);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_ta(ms) == qta/4);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
/*
* TS 44.060, B.8.1
@ -890,8 +893,8 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts,
ms = the_bts->ms_by_tlli(tlli);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->ta() == qta/4);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_ta(ms) == qta/4);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
/*
* TS 44.060, B.8.1
@ -1386,8 +1389,8 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_puan_URBB_no_length(BTS *t
ms = the_bts->ms_by_tlli(tlli);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->ta() == qta/4);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_ta(ms) == qta/4);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
return ul_tbf;
}
@ -1469,8 +1472,8 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_puan_URBB_with_length(BTS
ms = the_bts->ms_by_tlli(tlli);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->ta() == qta/4);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_ta(ms) == qta/4);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
return ul_tbf;
}
@ -1554,8 +1557,8 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_puan_CRBB(BTS *the_bts,
ms = the_bts->ms_by_tlli(tlli);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->ta() == qta/4);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_ta(ms) == qta/4);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
return ul_tbf;
}
@ -1637,8 +1640,8 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts,
ms = the_bts->ms_by_tlli(tlli);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->ta() == qta/4);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_ta(ms) == qta/4);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
return ul_tbf;
}
@ -1655,7 +1658,7 @@ static void send_dl_data(BTS *the_bts, uint32_t tlli, const char *imsi,
ms = the_bts->ms_by_imsi(imsi);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->dl_tbf() != NULL);
OSMO_ASSERT(ms_dl_tbf(ms) != NULL);
if (imsi[0] && strcmp(imsi, "000") != 0) {
ms2 = the_bts->ms_by_tlli(tlli);
@ -1672,7 +1675,7 @@ static void transmit_dl_data(BTS *the_bts, uint32_t tlli, uint32_t *fn,
ms = the_bts->ms_by_tlli(tlli);
OSMO_ASSERT(ms);
dl_tbf = ms->dl_tbf();
dl_tbf = ms_dl_tbf(ms);
OSMO_ASSERT(dl_tbf);
while (dl_tbf->have_data()) {
@ -1692,7 +1695,7 @@ static inline void print_ta_tlli(const gprs_rlcmac_ul_tbf *ul_tbf, bool print_ms
{
fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
if (print_ms)
fprintf(stderr, "Got MS: TLLI = 0x%08x, TA = %d\n", ul_tbf->ms()->tlli(), ul_tbf->ms()->ta());
fprintf(stderr, "Got MS: TLLI = 0x%08x, TA = %d\n", ms_tlli(ul_tbf->ms()), ms_ta(ul_tbf->ms()));
}
static void test_tbf_single_phase()
@ -1866,10 +1869,10 @@ static void test_tbf_two_phase()
fprintf(stderr, "=== end %s ===\n", __func__);
}
static inline void print_ms(const GprsMs *ms, bool old)
static inline void print_ms(GprsMs *ms, bool old)
{
fprintf(stderr, "%s MS: TLLI = 0x%08x, TA = %d, IMSI = %s, LLC = %zu\n",
old ? "Old" : "New", ms->tlli(), ms->ta(), ms->imsi(), ms->llc_queue()->size());
old ? "Old" : "New", ms_tlli(ms), ms_ta(ms), ms_imsi(ms), llc_queue_size(ms_llc_queue(ms)));
}
static void test_tbf_ra_update_rach()
@ -1905,9 +1908,9 @@ static void test_tbf_ra_update_rach()
send_control_ack(ul_tbf);
/* Make sure the RAU Accept gets sent to the MS */
OSMO_ASSERT(ms1->llc_queue()->size() == 1);
OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 1);
transmit_dl_data(&the_bts, tlli1, &fn);
OSMO_ASSERT(ms1->llc_queue()->size() == 0);
OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 0);
/* Now establish a new TBF for the RA UPDATE COMPLETE (new TLLI) */
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli2, &fn, qta,
@ -1963,8 +1966,8 @@ static void test_tbf_dl_flow_and_rach_two_phase()
send_dl_data(&the_bts, tlli1, imsi, (const uint8_t *)"DATA 2 *************", 20);
print_ms(ms1, true);
OSMO_ASSERT(ms1->llc_queue()->size() == 2);
dl_tbf = ms1->dl_tbf();
OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 2);
dl_tbf = ms_dl_tbf(ms1);
OSMO_ASSERT(dl_tbf != NULL);
/* Get rid of old UL TBF */
@ -1986,10 +1989,10 @@ static void test_tbf_dl_flow_and_rach_two_phase()
OSMO_ASSERT(ms2 == ms);
/* A DL TBF should still exist */
OSMO_ASSERT(ms->dl_tbf());
OSMO_ASSERT(ms_dl_tbf(ms));
/* No queued packets should be lost */
OSMO_ASSERT(ms->llc_queue()->size() == 2);
OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms)) == 2);
fprintf(stderr, "=== end %s ===\n", __func__);
}
@ -2022,8 +2025,8 @@ static void test_tbf_dl_flow_and_rach_single_phase()
send_dl_data(&the_bts, tlli1, imsi, (const uint8_t *)"DATA 2 *************", 20);
print_ms(ms1, true);
OSMO_ASSERT(ms1->llc_queue()->size() == 2);
dl_tbf = ms1->dl_tbf();
OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 2);
dl_tbf = ms_dl_tbf(ms1);
OSMO_ASSERT(dl_tbf != NULL);
/* Get rid of old UL TBF */
@ -2045,10 +2048,10 @@ static void test_tbf_dl_flow_and_rach_single_phase()
OSMO_ASSERT(ms1 != ms);
/* DL TBF should be removed */
OSMO_ASSERT(!ms->dl_tbf());
OSMO_ASSERT(!ms_dl_tbf(ms));
/* No queued packets should be lost */
OSMO_ASSERT(ms->llc_queue()->size() == 2);
OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms)) == 2);
fprintf(stderr, "=== end %s ===\n", __func__);
}
@ -2099,11 +2102,11 @@ static void test_tbf_dl_reuse()
/* Transmit all data */
transmit_dl_data(&the_bts, tlli1, &fn);
OSMO_ASSERT(ms1->llc_queue()->size() == 0);
OSMO_ASSERT(ms1->dl_tbf());
OSMO_ASSERT(ms1->dl_tbf()->state_is(GPRS_RLCMAC_FINISHED));
OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 0);
OSMO_ASSERT(ms_dl_tbf(ms1));
OSMO_ASSERT(ms_dl_tbf(ms1)->state_is(GPRS_RLCMAC_FINISHED));
dl_tbf1 = ms1->dl_tbf();
dl_tbf1 = ms_dl_tbf(ms1);
/* Send some LLC frames */
for (i = 0; i < 10; i++) {
@ -2132,10 +2135,10 @@ static void test_tbf_dl_reuse()
ms2 = the_bts.ms_by_tlli(tlli1);
OSMO_ASSERT(ms2 == ms1);
OSMO_ASSERT(ms2->dl_tbf());
OSMO_ASSERT(ms2->dl_tbf()->state_is(GPRS_RLCMAC_ASSIGN));
OSMO_ASSERT(ms_dl_tbf(ms2));
OSMO_ASSERT(ms_dl_tbf(ms2)->state_is(GPRS_RLCMAC_ASSIGN));
dl_tbf2 = ms2->dl_tbf();
dl_tbf2 = ms_dl_tbf(ms2);
OSMO_ASSERT(dl_tbf1 != dl_tbf2);
@ -2144,9 +2147,9 @@ static void test_tbf_dl_reuse()
/* Transmit all data */
transmit_dl_data(&the_bts, tlli1, &fn);
OSMO_ASSERT(ms2->llc_queue()->size() == 0);
OSMO_ASSERT(ms2->dl_tbf());
OSMO_ASSERT(ms2->dl_tbf()->state_is(GPRS_RLCMAC_FINISHED));
OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms2)) == 0);
OSMO_ASSERT(ms_dl_tbf(ms2));
OSMO_ASSERT(ms_dl_tbf(ms2)->state_is(GPRS_RLCMAC_FINISHED));
fprintf(stderr, "=== end %s ===\n", __func__);
}
@ -2411,8 +2414,8 @@ static gprs_rlcmac_ul_tbf *tbf_li_decoding(BTS *the_bts,
ms = the_bts->ms_by_tlli(tlli);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->ta() == qta/4);
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
OSMO_ASSERT(ms_ta(ms) == qta/4);
OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);
egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg;
egprs3->si = 0;
@ -2799,9 +2802,7 @@ static void egprs_spb_to_normal_validation(BTS *the_bts,
OSMO_ASSERT(bsn1 == 0);
dl_tbf->ms()->set_current_cs_dl
(static_cast < enum CodingScheme >
(CS4 + demanded_mcs));
ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + demanded_mcs));
fn = fn_add_blocks(fn, 1);
@ -2831,9 +2832,7 @@ static void egprs_spb_to_normal_validation(BTS *the_bts,
OSMO_ASSERT(egprs3->cps == 3);
/* Handle (MCS3, MCS3) -> MCS6 case */
dl_tbf->ms()->set_current_cs_dl
(static_cast < enum CodingScheme >
(CS4 + mcs));
ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + mcs));
NACK(dl_tbf, 0);
@ -2880,9 +2879,7 @@ static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts,
NACK(dl_tbf, 0);
dl_tbf->ms()->set_current_cs_dl
(static_cast < enum CodingScheme >
(CS4 + demanded_mcs));
ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + demanded_mcs));
fn = fn_add_blocks(fn, 1);
@ -2967,9 +2964,7 @@ static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts,
NACK(dl_tbf, 1);
/* Set the demanded MCS to demanded_mcs */
dl_tbf->ms()->set_current_cs_dl
(static_cast < enum CodingScheme >
(CS4 + demanded_mcs));
ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + demanded_mcs));
fn = fn_add_blocks(fn, 1);
/* Retransmit the first RLC data block with demanded_mcs */
@ -2994,9 +2989,7 @@ static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts,
NACK(dl_tbf, 0);
NACK(dl_tbf, 1);
dl_tbf->ms()->set_current_cs_dl
(static_cast < enum CodingScheme >
(CS4 + demanded_mcs));
ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + demanded_mcs));
fn = fn_add_blocks(fn, 1);
/* Send first, second RLC data blocks with demanded_mcs */
@ -3264,8 +3257,8 @@ int main(int argc, char **argv)
pcu_vty_init();
/* Initialize shared UL measurements */
meas.set_link_qual(12);
meas.set_rssi(31);
pcu_l1_meas_set_link_qual(&meas, 12);
pcu_l1_meas_set_rssi(&meas, 31);
test_tbf_base();
test_tbf_tlli_update();

View File

@ -58,27 +58,27 @@ static void test_llc(void)
gprs_llc llc;
llc.init();
OSMO_ASSERT(llc.chunk_size() == 0);
OSMO_ASSERT(llc.remaining_space() == LLC_MAX_LEN);
OSMO_ASSERT(llc.frame_length() == 0);
OSMO_ASSERT(llc_chunk_size(&llc) == 0);
OSMO_ASSERT(llc_remaining_space(&llc) == LLC_MAX_LEN);
OSMO_ASSERT(llc_frame_length(&llc) == 0);
llc.put_frame(data, 2);
OSMO_ASSERT(llc.remaining_space() == LLC_MAX_LEN - 2);
OSMO_ASSERT(llc.frame_length() == 2);
OSMO_ASSERT(llc.chunk_size() == 2);
OSMO_ASSERT(llc_remaining_space(&llc) == LLC_MAX_LEN - 2);
OSMO_ASSERT(llc_frame_length(&llc) == 2);
OSMO_ASSERT(llc_chunk_size(&llc) == 2);
OSMO_ASSERT(llc.frame[0] == 1);
OSMO_ASSERT(llc.frame[1] == 2);
llc.append_frame(&data[3], 1);
OSMO_ASSERT(llc.remaining_space() == LLC_MAX_LEN - 3);
OSMO_ASSERT(llc.frame_length() == 3);
OSMO_ASSERT(llc.chunk_size() == 3);
OSMO_ASSERT(llc_remaining_space(&llc) == LLC_MAX_LEN - 3);
OSMO_ASSERT(llc_frame_length(&llc) == 3);
OSMO_ASSERT(llc_chunk_size(&llc) == 3);
/* consume two bytes */
llc.consume(&out, 1);
OSMO_ASSERT(llc.remaining_space() == LLC_MAX_LEN - 3);
OSMO_ASSERT(llc.frame_length() == 3);
OSMO_ASSERT(llc.chunk_size() == 2);
llc_consume_data(&llc, &out, 1);
OSMO_ASSERT(llc_remaining_space(&llc) == LLC_MAX_LEN - 3);
OSMO_ASSERT(llc_frame_length(&llc) == 3);
OSMO_ASSERT(llc_chunk_size(&llc) == 2);
/* check that the bytes are as we expected */
OSMO_ASSERT(llc.frame[0] == 1);
@ -86,9 +86,9 @@ static void test_llc(void)
OSMO_ASSERT(llc.frame[2] == 4);
/* now fill the frame */
llc.append_frame(data, llc.remaining_space() - 1);
OSMO_ASSERT(llc.fits_in_current_frame(1));
OSMO_ASSERT(!llc.fits_in_current_frame(2));
llc.append_frame(data, llc_remaining_space(&llc) - 1);
OSMO_ASSERT(llc_fits_in_current_frame(&llc, 1));
OSMO_ASSERT(!llc_fits_in_current_frame(&llc, 2));
}
}