aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@espeweb.net>2020-12-16 15:59:45 +0100
committerpespin <pespin@sysmocom.de>2021-01-05 10:34:25 +0000
commitda971ee5026479e869ed75d944404d398c548497 (patch)
tree30bf447c2d828264e51d09f5422ea05421c48d47 /src
parent86fad1ec4e246110b9d8ae66fd7bc30e1cedb5de (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/bts.cpp51
-rw-r--r--src/bts.h16
-rw-r--r--src/encoding.cpp20
-rw-r--r--src/gprs_ms.c885
-rw-r--r--src/gprs_ms.cpp900
-rw-r--r--src/gprs_ms.h316
-rw-r--r--src/gprs_ms_storage.cpp64
-rw-r--r--src/gprs_ms_storage.h10
-rw-r--r--src/gprs_rlcmac_sched.cpp6
-rw-r--r--src/gprs_rlcmac_ts_alloc.cpp32
-rw-r--r--src/llc.cpp30
-rw-r--r--src/llc.h80
-rw-r--r--src/pcu_l1_if.cpp21
-rw-r--r--src/pcu_l1_if.h89
-rw-r--r--src/pcu_utils.h23
-rw-r--r--src/pcu_vty_functions.cpp98
-rw-r--r--src/pdch.cpp58
-rw-r--r--src/tbf.cpp106
-rw-r--r--src/tbf.h54
-rw-r--r--src/tbf_dl.cpp86
-rw-r--r--src/tbf_dl.h18
-rw-r--r--src/tbf_ul.cpp30
-rw-r--r--src/tbf_ul.h30
24 files changed, 1539 insertions, 1486 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index ece372d6..386a1f64 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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 \
diff --git a/src/bts.cpp b/src/bts.cpp
index b4f902ab..bd0a1d20 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -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();
+}
diff --git a/src/bts.h b/src/bts.h
index 055b131d..f10542f4 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -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
}
diff --git a/src/encoding.cpp b/src/encoding.cpp
index a16962ad..e7b1fb41 100644
--- a/src/encoding.cpp
+++ b/src/encoding.cpp
@@ -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;
diff --git a/src/gprs_ms.c b/src/gprs_ms.c
new file mode 100644
index 00000000..94f69cde
--- /dev/null
+++ b/src/gprs_ms.c
@@ -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;
+}
diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp
deleted file mode 100644
index c891cdfd..00000000
--- a/src/gprs_ms.cpp
+++ /dev/null
@@ -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;
-}
diff --git a/src/gprs_ms.h b/src/gprs_ms.h
index 8b8940bb..ade3f3ba 100644
--- a/src/gprs_ms.h
+++ b/src/gprs_ms.h
@@ -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);
+struct gpr_ms_callback {
+ void (*ms_idle)(struct GprsMs *);
+ void (*ms_active)(struct GprsMs *);
+};
- enum CodingScheme current_cs_ul() const;
- enum CodingScheme current_cs_dl() const;
- enum CodingScheme max_cs_ul() const;
- enum CodingScheme max_cs_dl() const;
+struct GprsMs {
+ struct llist_head list; /* list of all GprsMs */
+ struct gpr_ms_callback cb;
+ bool app_info_pending;
- 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);
+ 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 */
- gprs_llc_queue *llc_queue();
- const gprs_llc_queue *llc_queue() const;
- gprs_codel *codel_state() const;
+ uint32_t tlli;
+ uint32_t new_ul_tlli;
+ uint32_t new_dl_tlli;
- void set_timeout(unsigned secs);
+ /* 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;
- 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);
+ struct gprs_llc_queue llc_queue;
- void detach_tbf(gprs_rlcmac_tbf *tbf);
+ bool is_idle;
+ int ref;
+ struct osmo_timer_list timer;
+ unsigned delay;
- void update_error_rate(gprs_rlcmac_tbf *tbf, int percent);
+ int64_t last_cs_not_low;
- bool is_idle() const;
- bool need_dl_tbf() const;
+ 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;
- void* operator new(size_t num);
- void operator delete(void* p);
+ struct gprs_codel *codel_state;
+ enum mcs_kind mode;
- 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;}
+ unsigned dl_ctrl_msg;
+};
- 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();
+struct GprsMs *ms_alloc(struct BTS *bts, uint32_t tlli);
- /* internal use */
- static void timeout(void *priv_);
+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_);
- bool app_info_pending;
+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);
-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;
+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);
- /* 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;
+void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms);
- gprs_llc_queue m_llc_queue;
+void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);
+void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);
- bool m_is_idle;
- int m_ref;
- LListHead<GprsMs> m_list;
- struct osmo_timer_list m_timer;
- unsigned m_delay;
+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);
- int64_t m_last_cs_not_low;
+void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas);
- 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_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;}
- struct gprs_codel *m_codel_state;
- enum mcs_kind m_mode;
- unsigned m_dl_ctrl_msg;
-};
+void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb);
-inline bool GprsMs::is_idle() const
+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 false;
-
- return llc_queue()->size() > 0;
+ return &ms->llc_queue;
}
-inline uint32_t GprsMs::tlli() const
+static inline bool ms_need_dl_tbf(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_dl_tbf(ms) != NULL &&
+ tbf_state((const struct gprs_rlcmac_tbf *)ms_dl_tbf(ms)) != GPRS_RLCMAC_WAIT_RELEASE)
+ return false;
- return m_new_dl_tlli;
+ return llc_queue_size(ms_llc_queue(ms)) > 0;
}
-inline bool GprsMs::check_tlli(uint32_t tlli)
+static inline uint32_t ms_tlli(const struct GprsMs *ms)
{
- return tlli != GSM_RESERVED_TMSI &&
- (tlli == m_tlli || tlli == m_new_ul_tlli || tlli == m_new_dl_tlli);
-}
+ if (ms->new_ul_tlli != GSM_RESERVED_TMSI)
+ return ms->new_ul_tlli;
+ if (ms->tlli != GSM_RESERVED_TMSI)
+ return ms->tlli;
-inline const char *GprsMs::imsi() const
-{
- return m_imsi;
+ return ms->new_dl_tlli;
}
-inline uint8_t GprsMs::ta() const
+static inline bool ms_check_tlli(struct GprsMs *ms, uint32_t tlli)
{
- return m_ta;
+ return tlli != GSM_RESERVED_TMSI &&
+ (tlli == ms->tlli || tlli == ms->new_ul_tlli || tlli == ms->new_dl_tlli);
}
-inline uint8_t GprsMs::ms_class() const
+static inline const char *ms_imsi(const struct GprsMs *ms)
{
- return m_ms_class;
+ return ms->imsi;
}
-inline uint8_t GprsMs::egprs_ms_class() const
+static inline uint8_t ms_ta(const struct GprsMs *ms)
{
- return m_egprs_ms_class;
+ return ms->ta;
}
-inline enum CodingScheme GprsMs::current_cs_ul() const
+static inline uint8_t ms_ms_class(const struct GprsMs *ms)
{
- return m_current_cs_ul;
+ return ms->ms_class;
}
-inline enum mcs_kind GprsMs::mode() const
+static inline uint8_t ms_egprs_ms_class(const struct GprsMs *ms)
{
- return m_mode;
+ return ms->egprs_ms_class;
}
-inline void GprsMs::set_timeout(unsigned secs)
+static inline enum CodingScheme ms_current_cs_ul(const struct GprsMs *ms)
{
- m_delay = secs;
+ return ms->current_cs_ul;
}
-inline gprs_llc_queue *GprsMs::llc_queue()
+static inline enum mcs_kind ms_mode(const struct GprsMs *ms)
{
- return &m_llc_queue;
+ return ms->mode;
}
-inline const gprs_llc_queue *GprsMs::llc_queue() const
+static inline void ms_set_timeout(struct GprsMs *ms, unsigned secs)
{
- return &m_llc_queue;
+ ms->delay = secs;
}
-inline gprs_codel *GprsMs::codel_state() const
+static inline struct gprs_codel *ms_codel_state(const struct GprsMs *ms)
{
- return m_codel_state;
+ return ms->codel_state;
}
-inline unsigned GprsMs::nack_rate_dl() const
+static inline unsigned ms_nack_rate_dl(const struct GprsMs *ms)
{
- return m_nack_rate_dl;
+ return ms->nack_rate_dl;
}
-inline unsigned GprsMs::dl_ctrl_msg() const
+static inline unsigned ms_dl_ctrl_msg(const struct GprsMs *ms)
{
- return m_dl_ctrl_msg;
+ return ms->dl_ctrl_msg;
}
-inline void GprsMs::update_dl_ctrl_msg()
+static inline void ms_update_dl_ctrl_msg(struct GprsMs *ms)
{
- m_dl_ctrl_msg++;
+ ms->dl_ctrl_msg++;
}
-inline uint8_t GprsMs::reserved_dl_slots() const
+static inline uint8_t ms_reserved_dl_slots(const struct GprsMs *ms)
{
- return m_reserved_dl_slots;
+ return ms->reserved_dl_slots;
}
-inline uint8_t GprsMs::reserved_ul_slots() const
+static inline uint8_t ms_reserved_ul_slots(const struct GprsMs *ms)
{
- return m_reserved_ul_slots;
+ return ms->reserved_ul_slots;
}
-inline gprs_rlcmac_trx *GprsMs::current_trx() const
+static inline struct gprs_rlcmac_trx *ms_current_trx(const struct GprsMs *ms)
{
- 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
diff --git a/src/gprs_ms_storage.cpp b/src/gprs_ms_storage.cpp
index 73570b3a..6d5b09ec 100644
--- a/src/gprs_ms_storage.cpp
+++ b/src/gprs_ms_storage.cpp
@@ -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);
diff --git a/src/gprs_ms_storage.h b/src/gprs_ms_storage.h
index 35062f3d..af496887 100644
--- a/src/gprs_ms_storage.h
+++ b/src/gprs_ms_storage.h
@@ -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 */
};
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index 70d82373..caf121f1 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -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;
diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp
index 9551c598..1ef32f22 100644
--- a/src/gprs_rlcmac_ts_alloc.cpp
+++ b/src/gprs_rlcmac_ts_alloc.cpp
@@ -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;
}
diff --git a/src/llc.cpp b/src/llc.cpp
index e2d01c29..d1122f5c 100644
--- a/src/llc.cpp
+++ b/src/llc.cpp
@@ -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
diff --git a/src/llc.h b/src/llc.h
index 3c2e57a9..72fa62ea 100644
--- a/src/llc.h
+++ b/src/llc.h
@@ -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
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index a9845916..9cc62708 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -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;
diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h
index f86e7085..65fea9c5 100644
--- a/src/pcu_l1_if.h
+++ b/src/pcu_l1_if.h
@@ -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,
diff --git a/src/pcu_utils.h b/src/pcu_utils.h
index 8196a93f..cb2fd91a 100644
--- a/src/pcu_utils.h
+++ b/src/pcu_utils.h
@@ -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;
+};
diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp
index 416c006b..6100b136 100644
--- a/src/pcu_vty_functions.cpp
+++ b/src/pcu_vty_functions.cpp
@@ -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;
}
diff --git a/src/pdch.cpp b/src/pdch.cpp
index 4a0ff068..49cce8d3 100644
--- a/src/pdch.cpp
+++ b/src/pdch.cpp
@@ -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);
diff --git a/src/tbf.cpp b/src/tbf.cpp
index e92dfb64..fde44ba3 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -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();
+}
diff --git a/src/tbf.h b/src/tbf.h
index c97477bc..4bbfea2b 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -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
/*
@@ -182,6 +188,28 @@ enum tbf_counters { /* TBF counters from 3GPP TS 44.060 ยง13.4 */
#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 {
gprs_rlcmac_tbf(BTS *bts_, GprsMs *ms, gprs_rlcmac_tbf_direction dir);
@@ -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];
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index bb89e819..613f7b81 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -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;
+}
diff --git a/src/tbf_dl.h b/src/tbf_dl.h
index ffb370c3..3cd88c9e 100644
--- a/src/tbf_dl.h
+++ b/src/tbf_dl.h
@@ -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
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 80a8eaa4..f8c860c9 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -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;
+}
diff --git a/src/tbf_ul.h b/src/tbf_ul.h
index 9ccdf620..1d9cf50c 100644
--- a/src/tbf_ul.h
+++ b/src/tbf_ul.h
@@ -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