<p>pespin <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-pcu/+/21748">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Convert GprsMS and helpers classes to C<br><br>As we integrate osmo-pcu more and more with libosmocore features, it<br>becomes really hard to use them since libosmocore relies heavily on C<br>specific compilation features, which are not available in old C++<br>compilers (such as designated initializers for complex types in FSMs).<br><br>GprsMs is right now a quite simple object since initial design of<br>osmo-pcu made it optional and most of the logic was placed and stored<br>duplicated in TBF objects. However, that's changing as we introduce more<br>features, with the GprsMS class getting more weight. Hence, let's move<br>it now to be a C struct in order to be able to easily use libosmocore<br>features there, such as FSMs.<br><br>Some helper classes which GprsMs uses are also mostly move to C since<br>they are mostly structs with methods, so there's no point in having<br>duplicated APIs for C++ and C for such simple cases.<br><br>For some more complex classes, like (ul_,dl_)tbf, C API bindings are<br>added where needed so that GprsMs can use functionalitites from that<br>class. Most of those APIs can be kept afterwards and drop the C++ ones<br>since they provide no benefit in general.<br><br>Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c<br>---<br>M src/Makefile.am<br>M src/bts.cpp<br>M src/bts.h<br>M src/encoding.cpp<br>A src/gprs_ms.c<br>D src/gprs_ms.cpp<br>M src/gprs_ms.h<br>M src/gprs_ms_storage.cpp<br>M src/gprs_ms_storage.h<br>M src/gprs_rlcmac_sched.cpp<br>M src/gprs_rlcmac_ts_alloc.cpp<br>M src/llc.cpp<br>M src/llc.h<br>M src/pcu_l1_if.cpp<br>M src/pcu_l1_if.h<br>M src/pcu_utils.h<br>M src/pcu_vty_functions.cpp<br>M src/pdch.cpp<br>M src/tbf.cpp<br>M src/tbf.h<br>M src/tbf_dl.cpp<br>M src/tbf_dl.h<br>M src/tbf_ul.cpp<br>M src/tbf_ul.h<br>M tests/alloc/AllocTest.cpp<br>M tests/app_info/AppInfoTest.cpp<br>M tests/app_info/AppInfoTest.err<br>M tests/edge/EdgeTest.cpp<br>M tests/llc/LlcTest.cpp<br>M tests/ms/MsTest.cpp<br>M tests/tbf/TbfTest.cpp<br>M tests/types/TypesTest.cpp<br>32 files changed, 1,977 insertions(+), 1,920 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index ece372d..386a1f6 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -47,7 +47,7 @@</span><br><span>  gprs_rlcmac_sched.cpp \</span><br><span>      gprs_rlcmac_meas.cpp \</span><br><span>       gprs_rlcmac_ts_alloc.cpp \</span><br><span style="color: hsl(0, 100%, 40%);">-      gprs_ms.cpp \</span><br><span style="color: hsl(120, 100%, 40%);">+ gprs_ms.c \</span><br><span>  gprs_ms_storage.cpp \</span><br><span>        gsm_timer.cpp \</span><br><span>      pcu_l1_if.cpp \</span><br><span>diff --git a/src/bts.cpp b/src/bts.cpp</span><br><span>index b4f902a..bd0a1d2 100644</span><br><span>--- a/src/bts.cpp</span><br><span>+++ b/src/bts.cpp</span><br><span>@@ -712,7 +712,7 @@</span><br><span> </span><br><span>   ms = ms_by_tlli(tlli);</span><br><span>       if (ms)</span><br><span style="color: hsl(0, 100%, 40%);">-         dl_tbf = ms->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+             dl_tbf = ms_dl_tbf(ms);</span><br><span>      if (!dl_tbf) {</span><br><span>               LOGP(DRLCMAC, LOGL_ERROR, "Got IMM.ASS confirm, but TLLI=%08x "</span><br><span>                    "does not exit\n", tlli);</span><br><span>@@ -1140,9 +1140,9 @@</span><br><span>  GprsMs *ms;</span><br><span>  ms = ms_store().create_ms();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        ms->set_timeout(osmo_tdef_get(m_bts.T_defs_pcu, -2030, OSMO_TDEF_S, -1));</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_ms_class(ms_class);</span><br><span style="color: hsl(0, 100%, 40%);">-  ms->set_egprs_ms_class(egprs_ms_class);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_set_timeout(ms, osmo_tdef_get(m_bts.T_defs_pcu, -2030, OSMO_TDEF_S, -1));</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_set_ms_class(ms, ms_class);</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_set_egprs_ms_class(ms, egprs_ms_class);</span><br><span> </span><br><span>       return ms;</span><br><span> }</span><br><span>@@ -1206,22 +1206,22 @@</span><br><span>    }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void gprs_rlcmac_trx::reserve_slots(enum gprs_rlcmac_tbf_direction dir,</span><br><span style="color: hsl(120, 100%, 40%);">+void bts_trx_reserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir,</span><br><span>       uint8_t slots)</span><br><span> {</span><br><span>  unsigned i;</span><br><span style="color: hsl(0, 100%, 40%);">-     for (i = 0; i < ARRAY_SIZE(pdch); i += 1)</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < ARRAY_SIZE(trx->pdch); i += 1)</span><br><span>                 if (slots & (1 << i))</span><br><span style="color: hsl(0, 100%, 40%);">-                 pdch[i].reserve(dir);</span><br><span style="color: hsl(120, 100%, 40%);">+                 trx->pdch[i].reserve(dir);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void gprs_rlcmac_trx::unreserve_slots(enum gprs_rlcmac_tbf_direction dir,</span><br><span style="color: hsl(120, 100%, 40%);">+void bts_trx_unreserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir,</span><br><span>       uint8_t slots)</span><br><span> {</span><br><span>  unsigned i;</span><br><span style="color: hsl(0, 100%, 40%);">-     for (i = 0; i < ARRAY_SIZE(pdch); i += 1)</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < ARRAY_SIZE(trx->pdch); i += 1)</span><br><span>                 if (slots & (1 << i))</span><br><span style="color: hsl(0, 100%, 40%);">-                 pdch[i].unreserve(dir);</span><br><span style="color: hsl(120, 100%, 40%);">+                       trx->pdch[i].unreserve(dir);</span><br><span> }</span><br><span> </span><br><span> void bts_set_max_cs(struct gprs_rlcmac_bts *bts, uint8_t cs_dl, uint8_t cs_ul)</span><br><span>@@ -1277,3 +1277,34 @@</span><br><span>  bts->bts->set_max_mcs_dl(mcs_dl);</span><br><span>      bts->bts->set_max_mcs_ul(mcs_ul);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_bts *bts_data(struct BTS *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return &bts->m_bts;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs *bts_ms_by_imsi(struct BTS *bts, const char *imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return bts->ms_by_imsi(imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t bts_max_cs_dl(const struct BTS *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return bts->max_cs_dl();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t bts_max_cs_ul(const struct BTS *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return bts->max_cs_ul();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t bts_max_mcs_dl(const struct BTS *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return bts->max_mcs_dl();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t bts_max_mcs_ul(const struct BTS *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return bts->max_mcs_ul();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/bts.h b/src/bts.h</span><br><span>index 055b131..f10542f 100644</span><br><span>--- a/src/bts.h</span><br><span>+++ b/src/bts.h</span><br><span>@@ -90,15 +90,14 @@</span><br><span>       struct BTS *bts;</span><br><span>     uint8_t trx_no;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef __cplusplus</span><br><span style="color: hsl(0, 100%, 40%);">-   void reserve_slots(enum gprs_rlcmac_tbf_direction dir, uint8_t slots);</span><br><span style="color: hsl(0, 100%, 40%);">-  void unreserve_slots(enum gprs_rlcmac_tbf_direction dir, uint8_t slots);</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span> };</span><br><span> </span><br><span> #ifdef __cplusplus</span><br><span> extern "C" {</span><br><span> #endif</span><br><span style="color: hsl(120, 100%, 40%);">+void bts_trx_reserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir, uint8_t slots);</span><br><span style="color: hsl(120, 100%, 40%);">+void bts_trx_unreserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir, uint8_t slots);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void bts_update_tbf_ta(const char *p, uint32_t fn, uint8_t trx_no, uint8_t ts, int8_t ta, bool is_rach);</span><br><span> #ifdef __cplusplus</span><br><span> }</span><br><span>@@ -372,10 +371,11 @@</span><br><span> </span><br><span>  LListHead<gprs_rlcmac_tbf>& ul_tbfs();</span><br><span>     LListHead<gprs_rlcmac_tbf>& dl_tbfs();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_rlcmac_bts m_bts;</span><br><span> private:</span><br><span>    int m_cur_fn;</span><br><span>        int m_cur_blk_fn;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct gprs_rlcmac_bts m_bts;</span><br><span>        uint8_t m_max_cs_dl, m_max_cs_ul;</span><br><span>    uint8_t m_max_mcs_dl, m_max_mcs_ul;</span><br><span>  PollController m_pollController;</span><br><span>@@ -459,11 +459,17 @@</span><br><span> extern "C" {</span><br><span> #endif</span><br><span>         void bts_cleanup();</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_rlcmac_bts *bts_data(struct BTS *bts);</span><br><span>   struct gprs_rlcmac_bts *bts_main_data();</span><br><span>     struct rate_ctr_group *bts_main_data_stats();</span><br><span>        struct osmo_stat_item_group *bts_main_data_stat_items();</span><br><span>     void bts_set_max_cs(struct gprs_rlcmac_bts *bts, uint8_t cs_dl, uint8_t cs_ul);</span><br><span>      void bts_set_max_mcs(struct gprs_rlcmac_bts *bts, uint8_t mcs_dl, uint8_t mcs_ul);</span><br><span style="color: hsl(120, 100%, 40%);">+    struct GprsMs *bts_ms_by_imsi(struct BTS *bts, const char *imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t bts_max_cs_dl(const struct BTS *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bts_max_cs_ul(const struct BTS *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bts_max_mcs_dl(const struct BTS *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t bts_max_mcs_ul(const struct BTS *bts);</span><br><span> #ifdef __cplusplus</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/encoding.cpp b/src/encoding.cpp</span><br><span>index a16962a..e7b1fb4 100644</span><br><span>--- a/src/encoding.cpp</span><br><span>+++ b/src/encoding.cpp</span><br><span>@@ -1388,7 +1388,7 @@</span><br><span>   delimiter = data_block + *num_chunks;</span><br><span>        e_pointer = (*num_chunks ? delimiter - 1 : NULL);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   chunk = llc->chunk_size();</span><br><span style="color: hsl(120, 100%, 40%);">+ chunk = llc_chunk_size(llc);</span><br><span>         space = rdbi->data_len - *offset;</span><br><span> </span><br><span>     /* if chunk will exceed block limit */</span><br><span>@@ -1402,7 +1402,7 @@</span><br><span>                       *e_pointer |= 0x02; /* set previous M bit = 1 */</span><br><span>             }</span><br><span>            /* fill only space */</span><br><span style="color: hsl(0, 100%, 40%);">-           llc->consume(data, space);</span><br><span style="color: hsl(120, 100%, 40%);">+         llc_consume_data(llc, data, space);</span><br><span>          if (count_payload)</span><br><span>                   *count_payload = space;</span><br><span>              /* return data block as message */</span><br><span>@@ -1421,7 +1421,7 @@</span><br><span>           if (e_pointer)</span><br><span>                       *e_pointer |= 0x01;</span><br><span>          /* fill space */</span><br><span style="color: hsl(0, 100%, 40%);">-                llc->consume(data, space);</span><br><span style="color: hsl(120, 100%, 40%);">+         llc_consume_data(llc, data, space);</span><br><span>          if (count_payload)</span><br><span>                   *count_payload = space;</span><br><span>              *offset = rdbi->data_len;</span><br><span>@@ -1454,7 +1454,7 @@</span><br><span>                 rdbi->e = 0; /* 0: extensions present */</span><br><span>          // no need to set e_pointer nor increase delimiter</span><br><span>           /* fill only space, which is 1 octet less than chunk */</span><br><span style="color: hsl(0, 100%, 40%);">-         llc->consume(data, space);</span><br><span style="color: hsl(120, 100%, 40%);">+         llc_consume_data(llc, data, space);</span><br><span>          if (count_payload)</span><br><span>                   *count_payload = space;</span><br><span>              /* return data block as message */</span><br><span>@@ -1485,7 +1485,7 @@</span><br><span>   rdbi->e = 0; /* 0: extensions present */</span><br><span>  (*num_chunks)++;</span><br><span>     /* copy (rest of) LLC frame to space and reset later */</span><br><span style="color: hsl(0, 100%, 40%);">- llc->consume(data, chunk);</span><br><span style="color: hsl(120, 100%, 40%);">+ llc_consume_data(llc, data, chunk);</span><br><span>  if (count_payload)</span><br><span>           *count_payload = chunk;</span><br><span>      data += chunk;</span><br><span>@@ -1536,7 +1536,7 @@</span><br><span>       prev_li = (struct rlc_li_field_egprs *)</span><br><span>              (*num_chunks ? delimiter - 1 : NULL);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       chunk = llc->chunk_size();</span><br><span style="color: hsl(120, 100%, 40%);">+ chunk = llc_chunk_size(llc);</span><br><span>         space = rdbi->data_len - *offset;</span><br><span> </span><br><span>     /* if chunk will exceed block limit */</span><br><span>@@ -1546,7 +1546,7 @@</span><br><span>                       "only remaining space, and we are done\n",</span><br><span>                         chunk, space);</span><br><span>               /* fill only space */</span><br><span style="color: hsl(0, 100%, 40%);">-           llc->consume(data, space);</span><br><span style="color: hsl(120, 100%, 40%);">+         llc_consume_data(llc, data, space);</span><br><span>          if (count_payload)</span><br><span>                   *count_payload = space;</span><br><span>              /* return data block as message */</span><br><span>@@ -1562,7 +1562,7 @@</span><br><span>                   "this is a final block, we don't add length "</span><br><span>                  "header, and we are done\n", chunk, space);</span><br><span>                /* fill space */</span><br><span style="color: hsl(0, 100%, 40%);">-                llc->consume(data, space);</span><br><span style="color: hsl(120, 100%, 40%);">+         llc_consume_data(llc, data, space);</span><br><span>          if (count_payload)</span><br><span>                   *count_payload = space;</span><br><span>              *offset = rdbi->data_len;</span><br><span>@@ -1578,7 +1578,7 @@</span><br><span>                         "to start with an empty chunk\n",</span><br><span>                  chunk, space);</span><br><span>               /* fill space */</span><br><span style="color: hsl(0, 100%, 40%);">-                llc->consume(data, space);</span><br><span style="color: hsl(120, 100%, 40%);">+         llc_consume_data(llc, data, space);</span><br><span>          if (count_payload)</span><br><span>                   *count_payload = space;</span><br><span>              *offset = rdbi->data_len;</span><br><span>@@ -1610,7 +1610,7 @@</span><br><span>         prev_li = li;</span><br><span>        (*num_chunks)++;</span><br><span>     /* copy (rest of) LLC frame to space and reset later */</span><br><span style="color: hsl(0, 100%, 40%);">- llc->consume(data, chunk);</span><br><span style="color: hsl(120, 100%, 40%);">+ llc_consume_data(llc, data, chunk);</span><br><span>  if (count_payload)</span><br><span>           *count_payload = chunk;</span><br><span>      data += chunk;</span><br><span>diff --git a/src/gprs_ms.c b/src/gprs_ms.c</span><br><span>new file mode 100644</span><br><span>index 0000000..94f69cd</span><br><span>--- /dev/null</span><br><span>+++ b/src/gprs_ms.c</span><br><span>@@ -0,0 +1,885 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* gprs_ms.c</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2015-2020 by Sysmocom s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Jacob Erlbeck <jerlbeck@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or</span><br><span style="color: hsl(120, 100%, 40%);">+ * modify it under the terms of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * as published by the Free Software Foundation; either version 2</span><br><span style="color: hsl(120, 100%, 40%);">+ * of the License, or (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program; if not, write to the Free Software</span><br><span style="color: hsl(120, 100%, 40%);">+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ms.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "bts.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "tbf.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "tbf_ul.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_debug.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_codel.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "pcu_utils.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <time.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_04_08.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "coding_scheme.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define GPRS_CODEL_SLOW_INTERVAL_MS 4000</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern void *tall_pcu_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int64_t now_msec()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timespec ts;</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_clock_gettime(CLOCK_MONOTONIC, &ts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return (int64_t)(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_default_cb_ms_idle(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   talloc_free(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_default_cb_ms_active(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   /* do nothing */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gpr_ms_callback gprs_default_cb = {</span><br><span style="color: hsl(120, 100%, 40%);">+      .ms_idle = gprs_default_cb_ms_idle,</span><br><span style="color: hsl(120, 100%, 40%);">+   .ms_active = gprs_default_cb_ms_active,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_timeout(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct GprsMs *ms = (struct GprsMs *) data;</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_tlli(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ms->timer.data) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ms->timer.data = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+             ms_unref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ms_talloc_destructor(struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs *ms_alloc(struct BTS *bts, uint32_t tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct GprsMs *ms = talloc_zero(tall_pcu_ctx, struct GprsMs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       talloc_set_destructor(ms, ms_talloc_destructor);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ms->bts = bts;</span><br><span style="color: hsl(120, 100%, 40%);">+     ms->cb = gprs_default_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+  ms->tlli = tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+   ms->new_ul_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+       ms->new_dl_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+       ms->ta = GSM48_TA_INVALID;</span><br><span style="color: hsl(120, 100%, 40%);">+ ms->current_cs_ul = UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+       ms->current_cs_dl = UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+       ms->is_idle = true;</span><br><span style="color: hsl(120, 100%, 40%);">+        INIT_LLIST_HEAD(&ms->list);</span><br><span style="color: hsl(120, 100%, 40%);">+    INIT_LLIST_HEAD(&ms->old_tbfs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      int codel_interval = LLC_CODEL_USE_DEFAULT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ms->imsi[0] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+        memset(&ms->timer, 0, sizeof(ms->timer));</span><br><span style="color: hsl(120, 100%, 40%);">+   ms->timer.cb = ms_timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+ llc_queue_init(&ms->llc_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_mode(ms, GPRS);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ms->bts)</span><br><span style="color: hsl(120, 100%, 40%);">+               codel_interval = bts_data(ms->bts)->llc_codel_interval_msec;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (codel_interval) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (codel_interval == LLC_CODEL_USE_DEFAULT)</span><br><span style="color: hsl(120, 100%, 40%);">+                  codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;</span><br><span style="color: hsl(120, 100%, 40%);">+         ms->codel_state = talloc(ms, struct gprs_codel);</span><br><span style="color: hsl(120, 100%, 40%);">+           gprs_codel_init(ms->codel_state);</span><br><span style="color: hsl(120, 100%, 40%);">+          gprs_codel_set_interval(ms->codel_state, codel_interval);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     ms->last_cs_not_low = now_msec();</span><br><span style="color: hsl(120, 100%, 40%);">+  ms->app_info_pending = false;</span><br><span style="color: hsl(120, 100%, 40%);">+      return ms;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ms_talloc_destructor(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_item *pos, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", ms_tlli(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_set_reserved_slots(ms, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (osmo_timer_pending(&ms->timer))</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_timer_del(&ms->timer);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ms->ul_tbf) {</span><br><span style="color: hsl(120, 100%, 40%);">+          tbf_set_ms((struct gprs_rlcmac_tbf *)ms->ul_tbf, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms->ul_tbf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ms->dl_tbf) {</span><br><span style="color: hsl(120, 100%, 40%);">+          tbf_set_ms((struct gprs_rlcmac_tbf *)ms->dl_tbf, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms->dl_tbf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)pos->entry;</span><br><span style="color: hsl(120, 100%, 40%);">+                tbf_set_ms(tbf, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llc_queue_clear(&ms->llc_queue, ms->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (cb)</span><br><span style="color: hsl(120, 100%, 40%);">+               ms->cb = *cb;</span><br><span style="color: hsl(120, 100%, 40%);">+      else</span><br><span style="color: hsl(120, 100%, 40%);">+          ms->cb = gprs_default_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_update_status(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ms->ref > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ms_is_idle(ms) && !ms->is_idle) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ms->is_idle = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                ms->cb.ms_idle(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+                /* this can be deleted by now, do not access it */</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ms_is_idle(ms) && ms->is_idle) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ms->is_idle = false;</span><br><span style="color: hsl(120, 100%, 40%);">+               ms->cb.ms_active(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs *ms_ref(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   ms->ref += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      return ms;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_unref(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms->ref >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms->ref -= 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ms->ref == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_update_status(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_start_timer(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ms->delay == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ms->timer.data)</span><br><span style="color: hsl(120, 100%, 40%);">+               ms->timer.data = ms_ref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_timer_schedule(&ms->timer, ms->delay, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_stop_timer(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ms->timer.data)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_timer_del(&ms->timer);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms->timer.data = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     ms_unref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        ms->mode = mode;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ms->bts)</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (ms->mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS:</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!mcs_is_gprs(ms->current_cs_ul)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms->current_cs_ul = mcs_get_gprs_by_num(</span><br><span style="color: hsl(120, 100%, 40%);">+                           bts_data(ms->bts)->initial_cs_ul);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!mcs_is_valid(ms->current_cs_ul))</span><br><span style="color: hsl(120, 100%, 40%);">+                              ms->current_cs_ul = CS1;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!mcs_is_gprs(ms->current_cs_dl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms->current_cs_dl = mcs_get_gprs_by_num(</span><br><span style="color: hsl(120, 100%, 40%);">+                           bts_data(ms->bts)->initial_cs_dl);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!mcs_is_valid(ms->current_cs_dl))</span><br><span style="color: hsl(120, 100%, 40%);">+                              ms->current_cs_dl = CS1;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case EGPRS_GMSK:</span><br><span style="color: hsl(120, 100%, 40%);">+      case EGPRS:</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!mcs_is_edge(ms->current_cs_ul)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms->current_cs_ul = mcs_get_egprs_by_num(</span><br><span style="color: hsl(120, 100%, 40%);">+                          bts_data(ms->bts)->initial_mcs_ul);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!mcs_is_valid(ms->current_cs_ul))</span><br><span style="color: hsl(120, 100%, 40%);">+                              ms->current_cs_ul = MCS1;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!mcs_is_edge(ms->current_cs_dl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms->current_cs_dl = mcs_get_egprs_by_num(</span><br><span style="color: hsl(120, 100%, 40%);">+                          bts_data(ms->bts)->initial_mcs_dl);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!mcs_is_valid(ms->current_cs_dl))</span><br><span style="color: hsl(120, 100%, 40%);">+                              ms->current_cs_dl = MCS1;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_attach_ul_tbf(struct GprsMs *ms, struct gprs_rlcmac_ul_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ms->ul_tbf == tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           ms_tlli(ms), tbf_name((struct gprs_rlcmac_tbf *)tbf));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_ref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ms->ul_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_add_tail(tbf_ms_list((struct gprs_rlcmac_tbf *)ms->ul_tbf), &ms->old_tbfs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ms->ul_tbf = tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_stop_timer(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_unref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_attach_dl_tbf(struct GprsMs *ms, struct gprs_rlcmac_dl_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms->dl_tbf == tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           ms_tlli(ms), tbf_name((struct gprs_rlcmac_tbf *)tbf));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_ref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ms->dl_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_add_tail(tbf_ms_list((struct gprs_rlcmac_tbf *)ms->dl_tbf), &ms->old_tbfs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ms->dl_tbf = tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_stop_timer(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_unref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF)</span><br><span style="color: hsl(120, 100%, 40%);">+         ms_attach_dl_tbf(ms, as_dl_tbf(tbf));</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_attach_ul_tbf(ms, as_ul_tbf(tbf));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tbf == (struct gprs_rlcmac_tbf *)(ms->ul_tbf)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ms->ul_tbf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (tbf == (struct gprs_rlcmac_tbf *)(ms->dl_tbf)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ms->dl_tbf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              bool found = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         struct llist_item *pos, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+         llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gprs_rlcmac_tbf *tmp_tbf = (struct gprs_rlcmac_tbf *)pos->entry;</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (tmp_tbf == tbf) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         llist_del(&pos->list);</span><br><span style="color: hsl(120, 100%, 40%);">+                         found = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                         break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Protect against recursive calls via set_ms() */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!found)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         ms_tlli(ms), tbf_name(tbf));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (tbf_ms(tbf) == ms)</span><br><span style="color: hsl(120, 100%, 40%);">+                tbf_set_ms(tbf, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!ms->dl_tbf && !ms->ul_tbf) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ms_set_reserved_slots(ms, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ms_tlli(ms) != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                 ms_start_timer(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_update_status(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_reset(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           ms_tlli(ms), ms_imsi(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_stop_timer(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ms->tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+      ms->new_dl_tlli = ms->tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+     ms->new_ul_tlli = ms->tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+     ms->imsi[0] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_merge_old_ms(struct GprsMs *ms, struct GprsMs *old_ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(old_ms != ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (strlen(ms_imsi(ms)) == 0 && strlen(ms_imsi(old_ms)) != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_strlcpy(ms->imsi, ms_imsi(old_ms), sizeof(ms->imsi));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ms_ms_class(ms) && ms_ms_class(old_ms))</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_set_ms_class(ms, ms_ms_class(old_ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ms_egprs_ms_class(ms) && ms_egprs_ms_class(old_ms))</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_set_egprs_ms_class(ms, ms_egprs_ms_class(old_ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       llc_queue_move_and_merge(&ms->llc_queue, &old_ms->llc_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_reset(old_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(old_ms != ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_ref(old_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Clean up the old MS object */</span><br><span style="color: hsl(120, 100%, 40%);">+      /* TODO: Use timer? */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms_ul_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms), T_MAX))</span><br><span style="color: hsl(120, 100%, 40%);">+                     tbf_free((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms));</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms_dl_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms), T_MAX))</span><br><span style="color: hsl(120, 100%, 40%);">+                     tbf_free((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_merge_old_ms(ms, old_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_unref(old_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_tlli(struct GprsMs *ms, uint32_t tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tlli == ms->tlli || tlli == ms->new_ul_tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tlli != ms->new_dl_tlli) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "</span><br><span style="color: hsl(120, 100%, 40%);">+                       "not yet confirmed\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ms_tlli(ms), tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+           ms->new_ul_tlli = tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "</span><br><span style="color: hsl(120, 100%, 40%);">+          "already confirmed partly\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               ms->tlli, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ms->tlli = tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+   ms->new_dl_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+       ms->new_ul_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (tlli == ms->tlli || tlli == ms->new_dl_tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (tlli != ms->new_ul_tlli) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* The MS has not sent a message with the new TLLI, which may</span><br><span style="color: hsl(120, 100%, 40%);">+          * happen according to the spec [TODO: add reference]. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "</span><br><span style="color: hsl(120, 100%, 40%);">+                   "partly confirmed\n", tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Use the network's idea of TLLI as candidate, this does not</span><br><span style="color: hsl(120, 100%, 40%);">+              * change the result value of tlli() */</span><br><span style="color: hsl(120, 100%, 40%);">+               ms->new_dl_tlli = tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+            return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ms->tlli = tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+   ms->new_dl_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+       ms->new_ul_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_imsi(struct GprsMs *ms, const char *imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!imsi) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (imsi[0] && strlen(imsi) < 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (strcmp(imsi, ms->imsi) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               ms_tlli(ms), ms->imsi, imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct GprsMs *old_ms = bts_ms_by_imsi(ms->bts, imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Check if we are going to store a different MS object with already</span><br><span style="color: hsl(120, 100%, 40%);">+     existing IMSI. This is probably a bug in code calling this function,</span><br><span style="color: hsl(120, 100%, 40%);">+          since it should take care of this explicitly */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (old_ms) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* We cannot find ms->ms by IMSI since we know that it has a</span><br><span style="color: hsl(120, 100%, 40%);">+               * different IMSI */</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(old_ms != ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGPMS(ms, DRLCMAC, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "IMSI '%s' was already assigned to another "</span><br><span style="color: hsl(120, 100%, 40%);">+                "MS object: TLLI = 0x%08x, that IMSI will be removed\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    imsi, ms_tlli(old_ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_merge_and_clear_ms(ms, old_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_strlcpy(ms->imsi, imsi, sizeof(ms->imsi));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_ta(struct GprsMs *ms, uint8_t ta_)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ta_ == ms->ta)</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (gsm48_ta_is_valid(ta_)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms_tlli(ms), ms->ta, ta_);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms->ta = ta_;</span><br><span style="color: hsl(120, 100%, 40%);">+      } else</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DRLCMAC, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                 "MS object, TLLI = 0x%08x, invalid TA %d rejected (old "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "value %d kept)\n", ms_tlli(ms), ta_, ms->ta);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_ms_class(struct GprsMs *ms, uint8_t ms_class_)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ms_class_ == ms->ms_class)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               ms_tlli(ms), ms->ms_class, ms_class_);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ms->ms_class = ms_class_;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_egprs_ms_class(struct GprsMs *ms, uint8_t ms_class_)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms_class_ == ms->egprs_ms_class)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         ms_tlli(ms), ms->egprs_ms_class, ms_class_);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ms->egprs_ms_class = ms_class_;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!bts_max_mcs_ul(ms->bts) || !bts_max_mcs_dl(ms->bts)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPMS(ms, DRLCMAC, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Avoid enabling EGPRS because use of MCS is disabled: ul=%u dl=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        bts_max_mcs_ul(ms->bts), bts_max_mcs_dl(ms->bts));</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts))) &&</span><br><span style="color: hsl(120, 100%, 40%);">+             mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts))) &&</span><br><span style="color: hsl(120, 100%, 40%);">+         ms_mode(ms) != EGPRS)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+             ms_set_mode(ms, EGPRS_GMSK);</span><br><span style="color: hsl(120, 100%, 40%);">+  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_set_mode(ms, EGPRS);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPMS(ms, DRLCMAC, LOGL_INFO, "Enabled EGPRS, mode %s\n", mode_name(ms_mode(ms)));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_update_error_rate(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, int error_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_rlcmac_bts *bts_;</span><br><span style="color: hsl(120, 100%, 40%);">+ int64_t now;</span><br><span style="color: hsl(120, 100%, 40%);">+  enum CodingScheme max_cs_dl = ms_max_cs_dl(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(max_cs_dl);</span><br><span style="color: hsl(120, 100%, 40%);">+       bts_ = bts_data(ms->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (error_rate < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     now = now_msec();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* TODO: Check for TBF direction */</span><br><span style="color: hsl(120, 100%, 40%);">+   /* TODO: Support different CS values for UL and DL */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ms->nack_rate_dl = error_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (error_rate > bts_->cs_adj_upper_limit) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (mcs_chan_code(ms->current_cs_dl) > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     mcs_dec_kind(&ms->current_cs_dl, ms_mode(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOGP(DRLCMACDL, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "MS (IMSI %s): High error rate %d%%, "</span><br><span style="color: hsl(120, 100%, 40%);">+                              "reducing CS level to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                ms_imsi(ms), error_rate, mcs_name(ms->current_cs_dl));</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms->last_cs_not_low = now;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (error_rate < bts_->cs_adj_lower_limit) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (ms->current_cs_dl < max_cs_dl) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (now - ms->last_cs_not_low > 1000) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         mcs_inc_kind(&ms->current_cs_dl, ms_mode(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOGP(DRLCMACDL, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    "MS (IMSI %s): Low error rate %d%%, "</span><br><span style="color: hsl(120, 100%, 40%);">+                                       "increasing DL CS level to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ms_imsi(ms), error_rate,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      mcs_name(ms->current_cs_dl));</span><br><span style="color: hsl(120, 100%, 40%);">+                              ms->last_cs_not_low = now;</span><br><span style="color: hsl(120, 100%, 40%);">+                 } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGP(DRLCMACDL, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   "MS (IMSI %s): Low error rate %d%%, "</span><br><span style="color: hsl(120, 100%, 40%);">+                                       "ignored (within blocking period)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       ms_imsi(ms), error_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DRLCMACDL, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "MS (IMSI %s): Medium error rate %d%%, ignored\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  ms_imsi(ms), error_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+             ms->last_cs_not_low = now;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum CodingScheme ms_max_cs_ul(const struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(ms->bts != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (mcs_is_gprs(ms->current_cs_ul)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!bts_max_cs_ul(ms->bts)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     return CS4;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           return mcs_get_gprs_by_num(bts_max_cs_ul(ms->bts));</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!mcs_is_edge(ms->current_cs_ul))</span><br><span style="color: hsl(120, 100%, 40%);">+               return UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (bts_max_mcs_ul(ms->bts))</span><br><span style="color: hsl(120, 100%, 40%);">+               return mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts));</span><br><span style="color: hsl(120, 100%, 40%);">+      else if (bts_max_cs_ul(ms->bts))</span><br><span style="color: hsl(120, 100%, 40%);">+           return mcs_get_gprs_by_num(bts_max_cs_ul(ms->bts));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return MCS4;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_current_cs_dl(struct GprsMs *ms, enum CodingScheme scheme)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  ms->current_cs_dl = scheme;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum CodingScheme ms_max_cs_dl(const struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms->bts != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (mcs_is_gprs(ms->current_cs_dl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!bts_max_cs_dl(ms->bts)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     return CS4;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           return mcs_get_gprs_by_num(bts_max_cs_dl(ms->bts));</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!mcs_is_edge(ms->current_cs_dl))</span><br><span style="color: hsl(120, 100%, 40%);">+               return UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (bts_max_mcs_dl(ms->bts))</span><br><span style="color: hsl(120, 100%, 40%);">+               return mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts));</span><br><span style="color: hsl(120, 100%, 40%);">+      else if (bts_max_cs_dl(ms->bts))</span><br><span style="color: hsl(120, 100%, 40%);">+           return mcs_get_gprs_by_num(bts_max_cs_dl(ms->bts));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return MCS4;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_update_cs_ul(struct GprsMs *ms, const struct pcu_l1_meas *meas)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_bts *bts_;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum CodingScheme max_cs_ul = ms_max_cs_ul(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     int old_link_qual;</span><br><span style="color: hsl(120, 100%, 40%);">+    int low;</span><br><span style="color: hsl(120, 100%, 40%);">+      int high;</span><br><span style="color: hsl(120, 100%, 40%);">+     enum CodingScheme new_cs_ul = ms->current_cs_ul;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t current_cs = mcs_chan_code(ms->current_cs_ul);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bts_ = bts_data(ms->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!max_cs_ul) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DRLCMACMEAS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                 "max_cs_ul cannot be derived (current UL CS: %s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        mcs_name(ms->current_cs_ul));</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ms->current_cs_ul) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DRLCMACMEAS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Unable to update UL (M)CS because it's not set: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 mcs_name(ms->current_cs_ul));</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!meas->have_link_qual) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DRLCMACMEAS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Unable to update UL (M)CS %s because we don't have link quality measurements.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              mcs_name(ms->current_cs_ul));</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (mcs_is_gprs(ms->current_cs_ul)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (current_cs >= MAX_GPRS_CS)</span><br><span style="color: hsl(120, 100%, 40%);">+                     current_cs = MAX_GPRS_CS - 1;</span><br><span style="color: hsl(120, 100%, 40%);">+         low  = bts_->cs_lqual_ranges[current_cs].low;</span><br><span style="color: hsl(120, 100%, 40%);">+              high = bts_->cs_lqual_ranges[current_cs].high;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (mcs_is_edge(ms->current_cs_ul)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (current_cs >= MAX_EDGE_MCS)</span><br><span style="color: hsl(120, 100%, 40%);">+                    current_cs = MAX_EDGE_MCS - 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                low  = bts_->mcs_lqual_ranges[current_cs].low;</span><br><span style="color: hsl(120, 100%, 40%);">+             high = bts_->mcs_lqual_ranges[current_cs].high;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DRLCMACMEAS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+              "Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   mcs_name(ms->current_cs_ul));</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* To avoid rapid changes of the coding scheme, we also take</span><br><span style="color: hsl(120, 100%, 40%);">+   * the old link quality value into account (if present). */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ms->l1_meas.have_link_qual)</span><br><span style="color: hsl(120, 100%, 40%);">+            old_link_qual = ms->l1_meas.link_qual;</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          old_link_qual = meas->link_qual;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (meas->link_qual < low &&  old_link_qual < low)</span><br><span style="color: hsl(120, 100%, 40%);">+           mcs_dec_kind(&new_cs_ul, ms_mode(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+    else if (meas->link_qual > high &&  old_link_qual > high &&</span><br><span style="color: hsl(120, 100%, 40%);">+          ms->current_cs_ul < max_cs_ul)</span><br><span style="color: hsl(120, 100%, 40%);">+          mcs_inc_kind(&new_cs_ul, ms_mode(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ms->current_cs_ul != new_cs_ul) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPMS(ms, DRLCMACMEAS, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "Link quality %ddB (old %ddB) left window [%d, %d], "</span><br><span style="color: hsl(120, 100%, 40%);">+                       "modifying uplink CS level: %s -> %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 meas->link_qual, old_link_qual,</span><br><span style="color: hsl(120, 100%, 40%);">+                    low, high,</span><br><span style="color: hsl(120, 100%, 40%);">+                    mcs_name(ms->current_cs_ul), mcs_name(new_cs_ul));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                ms->current_cs_ul = new_cs_ul;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_update_cs_ul(ms, meas);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (meas->have_rssi)</span><br><span style="color: hsl(120, 100%, 40%);">+               pcu_l1_meas_set_rssi(&ms->l1_meas, meas->rssi);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (meas->have_bto)</span><br><span style="color: hsl(120, 100%, 40%);">+                pcu_l1_meas_set_bto(&ms->l1_meas, meas->bto);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (meas->have_ber)</span><br><span style="color: hsl(120, 100%, 40%);">+                pcu_l1_meas_set_ber(&ms->l1_meas, meas->ber);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (meas->have_link_qual)</span><br><span style="color: hsl(120, 100%, 40%);">+          pcu_l1_meas_set_link_qual(&ms->l1_meas, meas->link_qual);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (meas->have_ms_rx_qual)</span><br><span style="color: hsl(120, 100%, 40%);">+         pcu_l1_meas_set_ms_rx_qual(&ms->l1_meas, meas->ms_rx_qual);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (meas->have_ms_c_value)</span><br><span style="color: hsl(120, 100%, 40%);">+         pcu_l1_meas_set_ms_c_value(&ms->l1_meas, meas->ms_c_value);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (meas->have_ms_sign_var)</span><br><span style="color: hsl(120, 100%, 40%);">+                pcu_l1_meas_set_ms_sign_var(&ms->l1_meas, meas->ms_sign_var);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (meas->have_ms_i_level) {</span><br><span style="color: hsl(120, 100%, 40%);">+               for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (meas->ts[i].have_ms_i_level)</span><br><span style="color: hsl(120, 100%, 40%);">+                           pcu_l1_meas_set_ms_i_level(&ms->l1_meas, i, meas->ts[i].ms_i_level);</span><br><span style="color: hsl(120, 100%, 40%);">+                        else</span><br><span style="color: hsl(120, 100%, 40%);">+                          ms->l1_meas.ts[i].have_ms_i_level = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum CodingScheme ms_current_cs_dl(const struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        enum CodingScheme cs = ms->current_cs_dl;</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t unencoded_octets;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ms->bts)</span><br><span style="color: hsl(120, 100%, 40%);">+              return cs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  unencoded_octets = llc_queue_octets(&ms->llc_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If the DL TBF is active, add number of unencoded chunk octets */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ms->dl_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            unencoded_octets += llc_chunk_size(tbf_llc((struct gprs_rlcmac_tbf *)ms->dl_tbf));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* There are many unencoded octets, don't reduce */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (unencoded_octets >= bts_data(ms->bts)->cs_downgrade_threshold)</span><br><span style="color: hsl(120, 100%, 40%);">+           return cs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* RF conditions are good, don't reduce */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms->nack_rate_dl < bts_data(ms->bts)->cs_adj_lower_limit)</span><br><span style="color: hsl(120, 100%, 40%);">+             return cs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* The throughput would probably be better if the CS level was reduced */</span><br><span style="color: hsl(120, 100%, 40%);">+     mcs_dec_kind(&cs, ms_mode(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (cs == CS2)</span><br><span style="color: hsl(120, 100%, 40%);">+                mcs_dec_kind(&cs, ms_mode(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return cs;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ms_first_common_ts(const struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ms->dl_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            return tbf_first_common_ts((struct gprs_rlcmac_tbf *)ms->dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms->ul_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            return tbf_first_common_ts((struct gprs_rlcmac_tbf *)ms->ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t ms_dl_slots(const struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t slots = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ms->dl_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            slots |= tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ms->ul_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            slots |= tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return slots;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t ms_ul_slots(const struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t slots = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ms->dl_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            slots |= tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ms->ul_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+            slots |= tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return slots;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t ms_current_pacch_slots(const struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t slots = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  bool is_dl_active = ms->dl_tbf && tbf_is_tfi_assigned((struct gprs_rlcmac_tbf *)ms->dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    bool is_ul_active = ms->ul_tbf && tbf_is_tfi_assigned((struct gprs_rlcmac_tbf *)ms->ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!is_dl_active && !is_ul_active)</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* see TS 44.060, 8.1.1.2.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (is_dl_active && !is_ul_active)</span><br><span style="color: hsl(120, 100%, 40%);">+            slots =  tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       else if (!is_dl_active && is_ul_active)</span><br><span style="color: hsl(120, 100%, 40%);">+               slots =  tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          slots =  tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf) &</span><br><span style="color: hsl(120, 100%, 40%);">+                   tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Assume a multislot class 1 device */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* TODO: For class 2 devices, this could be removed */</span><br><span style="color: hsl(120, 100%, 40%);">+        slots = pcu_lsb(slots);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return slots;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t ul_slots, uint8_t dl_slots)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms->current_trx) {</span><br><span style="color: hsl(120, 100%, 40%);">+             bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,</span><br><span style="color: hsl(120, 100%, 40%);">+                       ms->reserved_dl_slots);</span><br><span style="color: hsl(120, 100%, 40%);">+            bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,</span><br><span style="color: hsl(120, 100%, 40%);">+                       ms->reserved_ul_slots);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms->reserved_dl_slots = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+         ms->reserved_ul_slots = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     ms->current_trx = trx;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (trx) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ms->reserved_dl_slots = dl_slots;</span><br><span style="color: hsl(120, 100%, 40%);">+          ms->reserved_ul_slots = ul_slots;</span><br><span style="color: hsl(120, 100%, 40%);">+          bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,</span><br><span style="color: hsl(120, 100%, 40%);">+                 ms->reserved_dl_slots);</span><br><span style="color: hsl(120, 100%, 40%);">+            bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,</span><br><span style="color: hsl(120, 100%, 40%);">+                 ms->reserved_ul_slots);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_tbf *ms_tbf(const struct GprsMs *ms, enum gprs_rlcmac_tbf_direction dir)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (dir) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_RLCMAC_DL_TBF: return (struct gprs_rlcmac_tbf *)ms->dl_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+      case GPRS_RLCMAC_UL_TBF: return (struct gprs_rlcmac_tbf *)ms->ul_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp</span><br><span>deleted file mode 100644</span><br><span>index c891cdf..0000000</span><br><span>--- a/src/gprs_ms.cpp</span><br><span>+++ /dev/null</span><br><span>@@ -1,900 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-/* gprs_ms.cpp</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH</span><br><span style="color: hsl(0, 100%, 40%);">- * Author: Jacob Erlbeck <jerlbeck@sysmocom.de></span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is free software; you can redistribute it and/or</span><br><span style="color: hsl(0, 100%, 40%);">- * modify it under the terms of the GNU General Public License</span><br><span style="color: hsl(0, 100%, 40%);">- * as published by the Free Software Foundation; either version 2</span><br><span style="color: hsl(0, 100%, 40%);">- * of the License, or (at your option) any later version.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(0, 100%, 40%);">- * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(0, 100%, 40%);">- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(0, 100%, 40%);">- * GNU General Public License for more details.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(0, 100%, 40%);">- * along with this program; if not, write to the Free Software</span><br><span style="color: hsl(0, 100%, 40%);">- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include "gprs_ms.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "bts.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "tbf.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "tbf_ul.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "gprs_debug.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "gprs_codel.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "pcu_utils.h"</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <time.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-extern "C" {</span><br><span style="color: hsl(0, 100%, 40%);">-   #include <osmocom/core/talloc.h></span><br><span style="color: hsl(0, 100%, 40%);">-  #include <osmocom/core/utils.h></span><br><span style="color: hsl(0, 100%, 40%);">-   #include <osmocom/core/timer.h></span><br><span style="color: hsl(0, 100%, 40%);">-   #include <osmocom/gsm/protocol/gsm_04_08.h></span><br><span style="color: hsl(0, 100%, 40%);">-       #include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(0, 100%, 40%);">-    #include <osmocom/core/logging.h></span><br><span style="color: hsl(0, 100%, 40%);">- #include "coding_scheme.h"</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#define GPRS_CODEL_SLOW_INTERVAL_MS 4000</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-extern void *tall_pcu_ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int64_t now_msec()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct timespec ts;</span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_clock_gettime(CLOCK_MONOTONIC, &ts);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   return int64_t(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct GprsMsDefaultCallback: public GprsMs::Callback {</span><br><span style="color: hsl(0, 100%, 40%);">-        virtual void ms_idle(class GprsMs *ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-                delete ms;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       virtual void ms_active(class GprsMs *) {}</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static GprsMsDefaultCallback gprs_default_cb;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-GprsMs::Guard::Guard(GprsMs *ms) :</span><br><span style="color: hsl(0, 100%, 40%);">-      m_ms(ms ? ms->ref() : NULL)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-GprsMs::Guard::~Guard()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        if (m_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-               m_ms->unref();</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-bool GprsMs::Guard::is_idle() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!m_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-              return true;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return !m_ms->m_ul_tbf && !m_ms->m_dl_tbf && m_ms->m_ref == 1;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::timeout(void *priv_)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      GprsMs *ms = static_cast<GprsMs *>(priv_);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",</span><br><span style="color: hsl(0, 100%, 40%);">-            ms->tlli());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (ms->m_timer.data) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ms->m_timer.data = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-             ms->unref();</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-GprsMs::GprsMs(BTS *bts, uint32_t tlli) :</span><br><span style="color: hsl(0, 100%, 40%);">-     m_bts(bts),</span><br><span style="color: hsl(0, 100%, 40%);">-     m_cb(&gprs_default_cb),</span><br><span style="color: hsl(0, 100%, 40%);">-     m_ul_tbf(NULL),</span><br><span style="color: hsl(0, 100%, 40%);">- m_dl_tbf(NULL),</span><br><span style="color: hsl(0, 100%, 40%);">- m_tlli(tlli),</span><br><span style="color: hsl(0, 100%, 40%);">-   m_new_ul_tlli(GSM_RESERVED_TMSI),</span><br><span style="color: hsl(0, 100%, 40%);">-       m_new_dl_tlli(GSM_RESERVED_TMSI),</span><br><span style="color: hsl(0, 100%, 40%);">-       m_ta(GSM48_TA_INVALID),</span><br><span style="color: hsl(0, 100%, 40%);">- m_ms_class(0),</span><br><span style="color: hsl(0, 100%, 40%);">-  m_egprs_ms_class(0),</span><br><span style="color: hsl(0, 100%, 40%);">-    m_current_cs_ul(UNKNOWN),</span><br><span style="color: hsl(0, 100%, 40%);">-       m_current_cs_dl(UNKNOWN),</span><br><span style="color: hsl(0, 100%, 40%);">-       m_is_idle(true),</span><br><span style="color: hsl(0, 100%, 40%);">-        m_ref(0),</span><br><span style="color: hsl(0, 100%, 40%);">-       m_list(this),</span><br><span style="color: hsl(0, 100%, 40%);">-   m_delay(0),</span><br><span style="color: hsl(0, 100%, 40%);">-     m_nack_rate_dl(0),</span><br><span style="color: hsl(0, 100%, 40%);">-      m_reserved_dl_slots(0),</span><br><span style="color: hsl(0, 100%, 40%);">- m_reserved_ul_slots(0),</span><br><span style="color: hsl(0, 100%, 40%);">- m_current_trx(NULL),</span><br><span style="color: hsl(0, 100%, 40%);">-    m_codel_state(NULL),</span><br><span style="color: hsl(0, 100%, 40%);">-    m_mode(GPRS),</span><br><span style="color: hsl(0, 100%, 40%);">-   m_dl_ctrl_msg(0)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       int codel_interval = LLC_CODEL_USE_DEFAULT;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        m_imsi[0] = '\0';</span><br><span style="color: hsl(0, 100%, 40%);">-       memset(&m_timer, 0, sizeof(m_timer));</span><br><span style="color: hsl(0, 100%, 40%);">-       m_timer.cb = GprsMs::timeout;</span><br><span style="color: hsl(0, 100%, 40%);">-   m_llc_queue.init();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     set_mode(m_mode);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (m_bts)</span><br><span style="color: hsl(0, 100%, 40%);">-              codel_interval = m_bts->bts_data()->llc_codel_interval_msec;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (codel_interval) {</span><br><span style="color: hsl(0, 100%, 40%);">-           if (codel_interval == LLC_CODEL_USE_DEFAULT)</span><br><span style="color: hsl(0, 100%, 40%);">-                    codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;</span><br><span style="color: hsl(0, 100%, 40%);">-           m_codel_state = talloc(this, struct gprs_codel);</span><br><span style="color: hsl(0, 100%, 40%);">-                gprs_codel_init(m_codel_state);</span><br><span style="color: hsl(0, 100%, 40%);">-         gprs_codel_set_interval(m_codel_state, codel_interval);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       m_last_cs_not_low = now_msec();</span><br><span style="color: hsl(0, 100%, 40%);">- app_info_pending = false;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-GprsMs::~GprsMs()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    LListHead<gprs_rlcmac_tbf> *pos, *tmp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", tlli());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    set_reserved_slots(NULL, 0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (osmo_timer_pending(&m_timer))</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_timer_del(&m_timer);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (m_ul_tbf) {</span><br><span style="color: hsl(0, 100%, 40%);">-         m_ul_tbf->set_ms(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-              m_ul_tbf = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (m_dl_tbf) {</span><br><span style="color: hsl(0, 100%, 40%);">-         m_dl_tbf->set_ms(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-              m_dl_tbf = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       llist_for_each_safe(pos, tmp, &m_old_tbfs)</span><br><span style="color: hsl(0, 100%, 40%);">-          pos->entry()->set_ms(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       m_llc_queue.clear(m_bts);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void* GprsMs::operator new(size_t size)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      static void *tall_ms_ctx = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!tall_ms_ctx)</span><br><span style="color: hsl(0, 100%, 40%);">-               tall_ms_ctx = talloc_named_const(tall_pcu_ctx, 0, __PRETTY_FUNCTION__);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return talloc_size(tall_ms_ctx, size);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::operator delete(void* p)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   talloc_free(p);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-GprsMs *GprsMs::ref()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  m_ref += 1;</span><br><span style="color: hsl(0, 100%, 40%);">-     return this;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::unref()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(m_ref >= 0);</span><br><span style="color: hsl(0, 100%, 40%);">-     m_ref -= 1;</span><br><span style="color: hsl(0, 100%, 40%);">-     if (m_ref == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-         update_status();</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::start_timer()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    if (m_delay == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-               return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!m_timer.data)</span><br><span style="color: hsl(0, 100%, 40%);">-              m_timer.data = ref();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   osmo_timer_schedule(&m_timer, m_delay, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::stop_timer()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!m_timer.data)</span><br><span style="color: hsl(0, 100%, 40%);">-              return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_timer_del(&m_timer);</span><br><span style="color: hsl(0, 100%, 40%);">-   m_timer.data = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    unref();</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::set_mode(enum mcs_kind mode)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     m_mode = mode;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!m_bts)</span><br><span style="color: hsl(0, 100%, 40%);">-             return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (m_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">-       case GPRS:</span><br><span style="color: hsl(0, 100%, 40%);">-              if (!mcs_is_gprs(m_current_cs_ul)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    m_current_cs_ul = mcs_get_gprs_by_num(</span><br><span style="color: hsl(0, 100%, 40%);">-                          m_bts->bts_data()->initial_cs_ul);</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (!mcs_is_valid(m_current_cs_ul))</span><br><span style="color: hsl(0, 100%, 40%);">-                             m_current_cs_ul = CS1;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!mcs_is_gprs(m_current_cs_dl)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    m_current_cs_dl = mcs_get_gprs_by_num(</span><br><span style="color: hsl(0, 100%, 40%);">-                          m_bts->bts_data()->initial_cs_dl);</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (!mcs_is_valid(m_current_cs_dl))</span><br><span style="color: hsl(0, 100%, 40%);">-                             m_current_cs_dl = CS1;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  case EGPRS_GMSK:</span><br><span style="color: hsl(0, 100%, 40%);">-        case EGPRS:</span><br><span style="color: hsl(0, 100%, 40%);">-             if (!mcs_is_edge(m_current_cs_ul)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    m_current_cs_ul = mcs_get_egprs_by_num(</span><br><span style="color: hsl(0, 100%, 40%);">-                         m_bts->bts_data()->initial_mcs_ul);</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!mcs_is_valid(m_current_cs_ul))</span><br><span style="color: hsl(0, 100%, 40%);">-                             m_current_cs_ul = MCS1;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!mcs_is_edge(m_current_cs_dl)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    m_current_cs_dl = mcs_get_egprs_by_num(</span><br><span style="color: hsl(0, 100%, 40%);">-                         m_bts->bts_data()->initial_mcs_dl);</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!mcs_is_valid(m_current_cs_dl))</span><br><span style="color: hsl(0, 100%, 40%);">-                             m_current_cs_dl = MCS1;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- if (tbf->direction == GPRS_RLCMAC_DL_TBF)</span><br><span style="color: hsl(0, 100%, 40%);">-            attach_dl_tbf(as_dl_tbf(tbf));</span><br><span style="color: hsl(0, 100%, 40%);">-  else</span><br><span style="color: hsl(0, 100%, 40%);">-            attach_ul_tbf(as_ul_tbf(tbf));</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      if (m_ul_tbf == tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-            return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-             tlli(), tbf->name());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        Guard guard(this);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (m_ul_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           llist_add_tail(&m_ul_tbf->ms_list(), &m_old_tbfs);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   m_ul_tbf = tbf;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-                stop_timer();</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::attach_dl_tbf(struct gprs_rlcmac_dl_tbf *tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       if (m_dl_tbf == tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-            return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-             tlli(), tbf->name());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        Guard guard(this);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (m_dl_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           llist_add_tail(&m_dl_tbf->ms_list(), &m_old_tbfs);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   m_dl_tbf = tbf;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-                stop_timer();</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    if (tbf == static_cast<gprs_rlcmac_tbf *>(m_ul_tbf)) {</span><br><span style="color: hsl(0, 100%, 40%);">-            m_ul_tbf = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-        } else if (tbf == static_cast<gprs_rlcmac_tbf *>(m_dl_tbf)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             m_dl_tbf = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-        } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                bool found = false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             LListHead<gprs_rlcmac_tbf> *pos, *tmp;</span><br><span style="color: hsl(0, 100%, 40%);">-            llist_for_each_safe(pos, tmp, &m_old_tbfs) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (pos->entry() == tbf) {</span><br><span style="color: hsl(0, 100%, 40%);">-                           llist_del(pos);</span><br><span style="color: hsl(0, 100%, 40%);">-                         found = true;</span><br><span style="color: hsl(0, 100%, 40%);">-                           break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Protect against recursive calls via set_ms() */</span><br><span style="color: hsl(0, 100%, 40%);">-              if (!found)</span><br><span style="color: hsl(0, 100%, 40%);">-                     return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-           tlli(), tbf->name());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (tbf->ms() == this)</span><br><span style="color: hsl(0, 100%, 40%);">-               tbf->set_ms(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!m_dl_tbf && !m_ul_tbf) {</span><br><span style="color: hsl(0, 100%, 40%);">-           set_reserved_slots(NULL, 0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         if (tlli() != 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                        start_timer();</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       update_status();</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::update_status()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  if (m_ref > 0)</span><br><span style="color: hsl(0, 100%, 40%);">-               return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (is_idle() && !m_is_idle) {</span><br><span style="color: hsl(0, 100%, 40%);">-          m_is_idle = true;</span><br><span style="color: hsl(0, 100%, 40%);">-               m_cb->ms_idle(this);</span><br><span style="color: hsl(0, 100%, 40%);">-         /* this can be deleted by now, do not access it */</span><br><span style="color: hsl(0, 100%, 40%);">-              return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!is_idle() && m_is_idle) {</span><br><span style="color: hsl(0, 100%, 40%);">-          m_is_idle = false;</span><br><span style="color: hsl(0, 100%, 40%);">-              m_cb->ms_active(this);</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::reset()</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-             tlli(), imsi());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        stop_timer();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   m_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(0, 100%, 40%);">-     m_new_dl_tlli = m_tlli;</span><br><span style="color: hsl(0, 100%, 40%);">- m_new_ul_tlli = m_tlli;</span><br><span style="color: hsl(0, 100%, 40%);">- m_imsi[0] = '\0';</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::merge_old_ms(GprsMs *old_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(old_ms != this);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (strlen(imsi()) == 0 && strlen(old_ms->imsi()) != 0)</span><br><span style="color: hsl(0, 100%, 40%);">-              osmo_strlcpy(m_imsi, old_ms->imsi(), sizeof(m_imsi));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!ms_class() && old_ms->ms_class())</span><br><span style="color: hsl(0, 100%, 40%);">-               set_ms_class(old_ms->ms_class());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!egprs_ms_class() && old_ms->egprs_ms_class())</span><br><span style="color: hsl(0, 100%, 40%);">-           set_egprs_ms_class(old_ms->egprs_ms_class());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        m_llc_queue.move_and_merge(&old_ms->m_llc_queue);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        old_ms->reset();</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::merge_and_clear_ms(GprsMs *old_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(old_ms != this);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    GprsMs::Guard guard_old(old_ms);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* Clean up the old MS object */</span><br><span style="color: hsl(0, 100%, 40%);">-        /* TODO: Use timer? */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (old_ms->ul_tbf() && !old_ms->ul_tbf()->timers_pending(T_MAX))</span><br><span style="color: hsl(0, 100%, 40%);">-                      tbf_free(old_ms->ul_tbf());</span><br><span style="color: hsl(0, 100%, 40%);">-  if (old_ms->dl_tbf() && !old_ms->dl_tbf()->timers_pending(T_MAX))</span><br><span style="color: hsl(0, 100%, 40%);">-                      tbf_free(old_ms->dl_tbf());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  merge_old_ms(old_ms);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::set_tlli(uint32_t tlli)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     if (tlli == m_tlli || tlli == m_new_ul_tlli)</span><br><span style="color: hsl(0, 100%, 40%);">-            return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (tlli != m_new_dl_tlli) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                        "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "</span><br><span style="color: hsl(0, 100%, 40%);">-                 "not yet confirmed\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                        this->tlli(), tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-         m_new_ul_tlli = tlli;</span><br><span style="color: hsl(0, 100%, 40%);">-           return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "</span><br><span style="color: hsl(0, 100%, 40%);">-            "already confirmed partly\n",</span><br><span style="color: hsl(0, 100%, 40%);">-         m_tlli, tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  m_tlli = tlli;</span><br><span style="color: hsl(0, 100%, 40%);">-  m_new_dl_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(0, 100%, 40%);">-      m_new_ul_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-bool GprsMs::confirm_tlli(uint32_t tlli)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    if (tlli == m_tlli || tlli == m_new_dl_tlli)</span><br><span style="color: hsl(0, 100%, 40%);">-            return false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (tlli != m_new_ul_tlli) {</span><br><span style="color: hsl(0, 100%, 40%);">-            /* The MS has not sent a message with the new TLLI, which may</span><br><span style="color: hsl(0, 100%, 40%);">-            * happen according to the spec [TODO: add reference]. */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                        "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "</span><br><span style="color: hsl(0, 100%, 40%);">-                     "partly confirmed\n", tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-          /* Use the network's idea of TLLI as candidate, this does not</span><br><span style="color: hsl(0, 100%, 40%);">-                * change the result value of tlli() */</span><br><span style="color: hsl(0, 100%, 40%);">-         m_new_dl_tlli = tlli;</span><br><span style="color: hsl(0, 100%, 40%);">-           return false;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       m_tlli = tlli;</span><br><span style="color: hsl(0, 100%, 40%);">-  m_new_dl_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(0, 100%, 40%);">-      m_new_ul_tlli = GSM_RESERVED_TMSI;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      return true;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::set_imsi(const char *imsi)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!imsi) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (imsi[0] && strlen(imsi) < 3) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-          return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (strcmp(imsi, m_imsi) == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-          return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-         tlli(), m_imsi, imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  GprsMs *old_ms = m_bts->ms_store().get_ms(0, 0, imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Check if we are going to store a different MS object with already</span><br><span style="color: hsl(0, 100%, 40%);">-       existing IMSI. This is probably a bug in code calling this function,</span><br><span style="color: hsl(0, 100%, 40%);">-    since it should take care of this explicitly */</span><br><span style="color: hsl(0, 100%, 40%);">-      if (old_ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-           /* We cannot find m_ms by IMSI since we know that it has a</span><br><span style="color: hsl(0, 100%, 40%);">-              * different IMSI */</span><br><span style="color: hsl(0, 100%, 40%);">-             OSMO_ASSERT(old_ms != this);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGPMS(this, DRLCMAC, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                     "IMSI '%s' was already assigned to another "</span><br><span style="color: hsl(0, 100%, 40%);">-                  "MS object: TLLI = 0x%08x, that IMSI will be removed\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      imsi, old_ms->tlli());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                merge_and_clear_ms(old_ms);</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       osmo_strlcpy(m_imsi, imsi, sizeof(m_imsi));</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::set_ta(uint8_t ta_)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   if (ta_ == m_ta)</span><br><span style="color: hsl(0, 100%, 40%);">-                return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (gsm48_ta_is_valid(ta_)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                     "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               tlli(), m_ta, ta_);</span><br><span style="color: hsl(0, 100%, 40%);">-                m_ta = ta_;</span><br><span style="color: hsl(0, 100%, 40%);">-     } else</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DRLCMAC, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                   "MS object, TLLI = 0x%08x, invalid TA %d rejected (old "</span><br><span style="color: hsl(0, 100%, 40%);">-              "value %d kept)\n", tlli(), ta_, m_ta);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::set_ms_class(uint8_t ms_class_)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    if (ms_class_ == m_ms_class)</span><br><span style="color: hsl(0, 100%, 40%);">-            return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-         tlli(), m_ms_class, ms_class_);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- m_ms_class = ms_class_;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::set_egprs_ms_class(uint8_t ms_class_)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     if (ms_class_ == m_egprs_ms_class)</span><br><span style="color: hsl(0, 100%, 40%);">-              return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DRLCMAC, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-           tlli(), m_egprs_ms_class, ms_class_);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   m_egprs_ms_class = ms_class_;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!m_bts->max_mcs_ul() || !m_bts->max_mcs_dl()) {</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGPMS(this, DRLCMAC, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-                      "Avoid enabling EGPRS because use of MCS is disabled: ul=%u dl=%u\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  m_bts->max_mcs_ul(), m_bts->max_mcs_dl());</span><br><span style="color: hsl(0, 100%, 40%);">-                return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (mcs_is_edge_gmsk(mcs_get_egprs_by_num(m_bts->max_mcs_ul())) &&</span><br><span style="color: hsl(0, 100%, 40%);">-           mcs_is_edge_gmsk(mcs_get_egprs_by_num(m_bts->max_mcs_dl())) &&</span><br><span style="color: hsl(0, 100%, 40%);">-               mode() != EGPRS)</span><br><span style="color: hsl(0, 100%, 40%);">-        {</span><br><span style="color: hsl(0, 100%, 40%);">-               set_mode(EGPRS_GMSK);</span><br><span style="color: hsl(0, 100%, 40%);">-   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                set_mode(EGPRS);</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGPMS(this, DRLCMAC, LOGL_INFO, "Enabled EGPRS, mode %s\n", mode_name(mode()));</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gprs_rlcmac_bts *bts_data;</span><br><span style="color: hsl(0, 100%, 40%);">-       int64_t now;</span><br><span style="color: hsl(0, 100%, 40%);">-    enum CodingScheme max_cs_dl = this->max_cs_dl();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_ASSERT(max_cs_dl);</span><br><span style="color: hsl(0, 100%, 40%);">- bts_data = m_bts->bts_data();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (error_rate < 0)</span><br><span style="color: hsl(0, 100%, 40%);">-          return;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- now = now_msec();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* TODO: Check for TBF direction */</span><br><span style="color: hsl(0, 100%, 40%);">-     /* TODO: Support different CS values for UL and DL */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   m_nack_rate_dl = error_rate;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (error_rate > bts_data->cs_adj_upper_limit) {</span><br><span style="color: hsl(0, 100%, 40%);">-          if (mcs_chan_code(m_current_cs_dl) > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    mcs_dec_kind(&m_current_cs_dl, mode());</span><br><span style="color: hsl(0, 100%, 40%);">-                     LOGP(DRLCMACDL, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                              "MS (IMSI %s): High error rate %d%%, "</span><br><span style="color: hsl(0, 100%, 40%);">-                                "reducing CS level to %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                          imsi(), error_rate, mcs_name(m_current_cs_dl));</span><br><span style="color: hsl(0, 100%, 40%);">-                 m_last_cs_not_low = now;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-       } else if (error_rate < bts_data->cs_adj_lower_limit) {</span><br><span style="color: hsl(0, 100%, 40%);">-           if (m_current_cs_dl < max_cs_dl) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (now - m_last_cs_not_low > 1000) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        mcs_inc_kind(&m_current_cs_dl, mode());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                             LOGP(DRLCMACDL, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      "MS (IMSI %s): Low error rate %d%%, "</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "increasing DL CS level to %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                     imsi(), error_rate,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     mcs_name(m_current_cs_dl));</span><br><span style="color: hsl(0, 100%, 40%);">-                             m_last_cs_not_low = now;</span><br><span style="color: hsl(0, 100%, 40%);">-                } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGP(DRLCMACDL, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     "MS (IMSI %s): Low error rate %d%%, "</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "ignored (within blocking period)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                 imsi(), error_rate);</span><br><span style="color: hsl(0, 100%, 40%);">-                    }</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-       } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DRLCMACDL, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-                     "MS (IMSI %s): Medium error rate %d%%, ignored\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    imsi(), error_rate);</span><br><span style="color: hsl(0, 100%, 40%);">-            m_last_cs_not_low = now;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-enum CodingScheme GprsMs::max_cs_ul() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(m_bts != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (mcs_is_gprs(m_current_cs_ul)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (!m_bts->max_cs_ul()) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   return CS4;</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               return mcs_get_gprs_by_num(m_bts->max_cs_ul());</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!mcs_is_edge(m_current_cs_ul))</span><br><span style="color: hsl(0, 100%, 40%);">-              return UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (m_bts->max_mcs_ul())</span><br><span style="color: hsl(0, 100%, 40%);">-             return mcs_get_egprs_by_num(m_bts->max_mcs_ul());</span><br><span style="color: hsl(0, 100%, 40%);">-    else if (m_bts->max_cs_ul())</span><br><span style="color: hsl(0, 100%, 40%);">-         return mcs_get_gprs_by_num(m_bts->max_cs_ul());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      return MCS4;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::set_current_cs_dl(enum CodingScheme scheme)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  m_current_cs_dl = scheme;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-enum CodingScheme GprsMs::max_cs_dl() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(m_bts != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (mcs_is_gprs(m_current_cs_dl)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (!m_bts->max_cs_dl()) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   return CS4;</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               return mcs_get_gprs_by_num(m_bts->max_cs_dl());</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!mcs_is_edge(m_current_cs_dl))</span><br><span style="color: hsl(0, 100%, 40%);">-              return UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (m_bts->max_mcs_dl())</span><br><span style="color: hsl(0, 100%, 40%);">-             return mcs_get_egprs_by_num(m_bts->max_mcs_dl());</span><br><span style="color: hsl(0, 100%, 40%);">-    else if (m_bts->max_cs_dl())</span><br><span style="color: hsl(0, 100%, 40%);">-         return mcs_get_gprs_by_num(m_bts->max_cs_dl());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      return MCS4;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::update_cs_ul(const pcu_l1_meas *meas)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gprs_rlcmac_bts *bts_data;</span><br><span style="color: hsl(0, 100%, 40%);">-       enum CodingScheme max_cs_ul = this->max_cs_ul();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     int old_link_qual;</span><br><span style="color: hsl(0, 100%, 40%);">-      int low;</span><br><span style="color: hsl(0, 100%, 40%);">-        int high;</span><br><span style="color: hsl(0, 100%, 40%);">-       enum CodingScheme new_cs_ul = m_current_cs_ul;</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t current_cs = mcs_chan_code(m_current_cs_ul);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    bts_data = m_bts->bts_data();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!max_cs_ul) {</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DRLCMACMEAS, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                   "max_cs_ul cannot be derived (current UL CS: %s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  mcs_name(m_current_cs_ul));</span><br><span style="color: hsl(0, 100%, 40%);">-             return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!m_current_cs_ul) {</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGP(DRLCMACMEAS, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Unable to update UL (M)CS because it's not set: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                   mcs_name(m_current_cs_ul));</span><br><span style="color: hsl(0, 100%, 40%);">-                return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!meas->have_link_qual) {</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGP(DRLCMACMEAS, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Unable to update UL (M)CS %s because we don't have link quality measurements.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                mcs_name(m_current_cs_ul));</span><br><span style="color: hsl(0, 100%, 40%);">-                return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (mcs_is_gprs(m_current_cs_ul)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (current_cs >= MAX_GPRS_CS)</span><br><span style="color: hsl(0, 100%, 40%);">-                       current_cs = MAX_GPRS_CS - 1;</span><br><span style="color: hsl(0, 100%, 40%);">-           low  = bts_data->cs_lqual_ranges[current_cs].low;</span><br><span style="color: hsl(0, 100%, 40%);">-            high = bts_data->cs_lqual_ranges[current_cs].high;</span><br><span style="color: hsl(0, 100%, 40%);">-   } else if (mcs_is_edge(m_current_cs_ul)) {</span><br><span style="color: hsl(0, 100%, 40%);">-              if (current_cs >= MAX_EDGE_MCS)</span><br><span style="color: hsl(0, 100%, 40%);">-                      current_cs = MAX_EDGE_MCS - 1;</span><br><span style="color: hsl(0, 100%, 40%);">-          low  = bts_data->mcs_lqual_ranges[current_cs].low;</span><br><span style="color: hsl(0, 100%, 40%);">-           high = bts_data->mcs_lqual_ranges[current_cs].high;</span><br><span style="color: hsl(0, 100%, 40%);">-  } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DRLCMACMEAS, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                "Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     mcs_name(m_current_cs_ul));</span><br><span style="color: hsl(0, 100%, 40%);">-                return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* To avoid rapid changes of the coding scheme, we also take</span><br><span style="color: hsl(0, 100%, 40%);">-     * the old link quality value into account (if present). */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (m_l1_meas.have_link_qual)</span><br><span style="color: hsl(0, 100%, 40%);">-           old_link_qual = m_l1_meas.link_qual;</span><br><span style="color: hsl(0, 100%, 40%);">-    else</span><br><span style="color: hsl(0, 100%, 40%);">-            old_link_qual = meas->link_qual;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (meas->link_qual < low &&  old_link_qual < low)</span><br><span style="color: hsl(0, 100%, 40%);">-             mcs_dec_kind(&new_cs_ul, mode());</span><br><span style="color: hsl(0, 100%, 40%);">-   else if (meas->link_qual > high &&  old_link_qual > high &&</span><br><span style="color: hsl(0, 100%, 40%);">-            m_current_cs_ul < max_cs_ul)</span><br><span style="color: hsl(0, 100%, 40%);">-         mcs_inc_kind(&new_cs_ul, mode());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (m_current_cs_ul != new_cs_ul) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPMS(this, DRLCMACMEAS, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                   "Link quality %ddB (old %ddB) left window [%d, %d], "</span><br><span style="color: hsl(0, 100%, 40%);">-                 "modifying uplink CS level: %s -> %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                   meas->link_qual, old_link_qual,</span><br><span style="color: hsl(0, 100%, 40%);">-                      low, high,</span><br><span style="color: hsl(0, 100%, 40%);">-                      mcs_name(m_current_cs_ul), mcs_name(new_cs_ul));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         m_current_cs_ul = new_cs_ul;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::update_l1_meas(const pcu_l1_meas *meas)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned i;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     update_cs_ul(meas);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (meas->have_rssi)</span><br><span style="color: hsl(0, 100%, 40%);">-         m_l1_meas.set_rssi(meas->rssi);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (meas->have_bto)</span><br><span style="color: hsl(0, 100%, 40%);">-          m_l1_meas.set_bto(meas->bto);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (meas->have_ber)</span><br><span style="color: hsl(0, 100%, 40%);">-          m_l1_meas.set_ber(meas->ber);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (meas->have_link_qual)</span><br><span style="color: hsl(0, 100%, 40%);">-            m_l1_meas.set_link_qual(meas->link_qual);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (meas->have_ms_rx_qual)</span><br><span style="color: hsl(0, 100%, 40%);">-           m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (meas->have_ms_c_value)</span><br><span style="color: hsl(0, 100%, 40%);">-           m_l1_meas.set_ms_c_value(meas->ms_c_value);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (meas->have_ms_sign_var)</span><br><span style="color: hsl(0, 100%, 40%);">-          m_l1_meas.set_ms_sign_var(meas->ms_sign_var);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (meas->have_ms_i_level) {</span><br><span style="color: hsl(0, 100%, 40%);">-         for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      if (meas->ts[i].have_ms_i_level)</span><br><span style="color: hsl(0, 100%, 40%);">-                             m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level);</span><br><span style="color: hsl(0, 100%, 40%);">-                 else</span><br><span style="color: hsl(0, 100%, 40%);">-                            m_l1_meas.ts[i].have_ms_i_level = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-enum CodingScheme GprsMs::current_cs_dl() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      enum CodingScheme cs = m_current_cs_dl;</span><br><span style="color: hsl(0, 100%, 40%);">- size_t unencoded_octets;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!m_bts)</span><br><span style="color: hsl(0, 100%, 40%);">-             return cs;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      unencoded_octets = m_llc_queue.octets();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* If the DL TBF is active, add number of unencoded chunk octets */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (m_dl_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           unencoded_octets += m_dl_tbf->m_llc.chunk_size();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* There are many unencoded octets, don't reduce */</span><br><span style="color: hsl(0, 100%, 40%);">- if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)</span><br><span style="color: hsl(0, 100%, 40%);">-             return cs;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* RF conditions are good, don't reduce */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit)</span><br><span style="color: hsl(0, 100%, 40%);">-            return cs;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* The throughput would probably be better if the CS level was reduced */</span><br><span style="color: hsl(0, 100%, 40%);">-       mcs_dec_kind(&cs, mode());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (cs == CS2)</span><br><span style="color: hsl(0, 100%, 40%);">-          mcs_dec_kind(&cs, mode());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  return cs;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int GprsMs::first_common_ts() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- if (m_dl_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           return m_dl_tbf->first_common_ts;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (m_ul_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           return m_ul_tbf->first_common_ts;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-uint8_t GprsMs::dl_slots() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t slots = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (m_dl_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           slots |= m_dl_tbf->dl_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (m_ul_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           slots |= m_ul_tbf->dl_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return slots;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-uint8_t GprsMs::ul_slots() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t slots = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (m_dl_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           slots |= m_dl_tbf->ul_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (m_ul_tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-           slots |= m_ul_tbf->ul_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return slots;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-uint8_t GprsMs::current_pacch_slots() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      uint8_t slots = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      bool is_dl_active = m_dl_tbf && m_dl_tbf->is_tfi_assigned();</span><br><span style="color: hsl(0, 100%, 40%);">- bool is_ul_active = m_ul_tbf && m_ul_tbf->is_tfi_assigned();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!is_dl_active && !is_ul_active)</span><br><span style="color: hsl(0, 100%, 40%);">-             return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* see TS 44.060, 8.1.1.2.2 */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (is_dl_active && !is_ul_active)</span><br><span style="color: hsl(0, 100%, 40%);">-              slots =  m_dl_tbf->dl_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-       else if (!is_dl_active && is_ul_active)</span><br><span style="color: hsl(0, 100%, 40%);">-         slots =  m_ul_tbf->ul_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-       else</span><br><span style="color: hsl(0, 100%, 40%);">-            slots =  m_ul_tbf->ul_slots() & m_dl_tbf->dl_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Assume a multislot class 1 device */</span><br><span style="color: hsl(0, 100%, 40%);">- /* TODO: For class 2 devices, this could be removed */</span><br><span style="color: hsl(0, 100%, 40%);">-  slots = pcu_lsb(slots);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return slots;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMs::set_reserved_slots(gprs_rlcmac_trx *trx,</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t ul_slots, uint8_t dl_slots)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    if (m_current_trx) {</span><br><span style="color: hsl(0, 100%, 40%);">-            m_current_trx->unreserve_slots(GPRS_RLCMAC_DL_TBF,</span><br><span style="color: hsl(0, 100%, 40%);">-                   m_reserved_dl_slots);</span><br><span style="color: hsl(0, 100%, 40%);">-           m_current_trx->unreserve_slots(GPRS_RLCMAC_UL_TBF,</span><br><span style="color: hsl(0, 100%, 40%);">-                   m_reserved_ul_slots);</span><br><span style="color: hsl(0, 100%, 40%);">-           m_reserved_dl_slots = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                m_reserved_ul_slots = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       m_current_trx = trx;</span><br><span style="color: hsl(0, 100%, 40%);">-    if (trx) {</span><br><span style="color: hsl(0, 100%, 40%);">-              m_reserved_dl_slots = dl_slots;</span><br><span style="color: hsl(0, 100%, 40%);">-         m_reserved_ul_slots = ul_slots;</span><br><span style="color: hsl(0, 100%, 40%);">-         m_current_trx->reserve_slots(GPRS_RLCMAC_DL_TBF,</span><br><span style="color: hsl(0, 100%, 40%);">-                     m_reserved_dl_slots);</span><br><span style="color: hsl(0, 100%, 40%);">-           m_current_trx->reserve_slots(GPRS_RLCMAC_UL_TBF,</span><br><span style="color: hsl(0, 100%, 40%);">-                     m_reserved_ul_slots);</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-gprs_rlcmac_tbf *GprsMs::tbf(enum gprs_rlcmac_tbf_direction dir) const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       switch (dir) {</span><br><span style="color: hsl(0, 100%, 40%);">-  case GPRS_RLCMAC_DL_TBF: return m_dl_tbf;</span><br><span style="color: hsl(0, 100%, 40%);">-       case GPRS_RLCMAC_UL_TBF: return m_ul_tbf;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span>diff --git a/src/gprs_ms.h b/src/gprs_ms.h</span><br><span>index 8b8940b..ade3f3b 100644</span><br><span>--- a/src/gprs_ms.h</span><br><span>+++ b/src/gprs_ms.h</span><br><span>@@ -1,6 +1,6 @@</span><br><span> /* gprs_ms.h</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2015-2020 by Sysmocom s.f.m.c. GmbH</span><br><span>  * Author: Jacob Erlbeck <jerlbeck@sysmocom.de></span><br><span>  *</span><br><span>  * This program is free software; you can redistribute it and/or</span><br><span>@@ -22,22 +22,23 @@</span><br><span> </span><br><span> struct gprs_codel;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#include "cxx_linuxlist.h"</span><br><span> #include "llc.h"</span><br><span> #include "tbf.h"</span><br><span> #include "tbf_ul.h"</span><br><span> #include "tbf_dl.h"</span><br><span> #include "pcu_l1_if.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> extern "C" {</span><br><span style="color: hsl(0, 100%, 40%);">-      #include <osmocom/core/timer.h></span><br><span style="color: hsl(0, 100%, 40%);">-   #include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   #include <osmocom/gsm/protocol/gsm_23_003.h></span><br><span style="color: hsl(0, 100%, 40%);">-      #include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      #include "coding_scheme.h"</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_23_003.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "coding_scheme.h"</span><br><span> </span><br><span> #include <stdint.h></span><br><span> #include <stddef.h></span><br><span>@@ -45,268 +46,207 @@</span><br><span> </span><br><span> struct BTS;</span><br><span> struct gprs_rlcmac_trx;</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-class GprsMs {</span><br><span style="color: hsl(0, 100%, 40%);">-public:</span><br><span style="color: hsl(0, 100%, 40%);">-    struct Callback {</span><br><span style="color: hsl(0, 100%, 40%);">-               virtual void ms_idle(class GprsMs *) = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-               virtual void ms_active(class GprsMs *) = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      class Guard {</span><br><span style="color: hsl(0, 100%, 40%);">-           public:</span><br><span style="color: hsl(0, 100%, 40%);">-         Guard(GprsMs *ms);</span><br><span style="color: hsl(0, 100%, 40%);">-              ~Guard();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               bool is_idle() const;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           private:</span><br><span style="color: hsl(0, 100%, 40%);">-                GprsMs * const m_ms;</span><br><span style="color: hsl(0, 100%, 40%);">-    };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      GprsMs(BTS *bts, uint32_t tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-        ~GprsMs();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      void set_callback(Callback *cb) {m_cb = cb;}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    void merge_and_clear_ms(GprsMs *old_ms);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        gprs_rlcmac_ul_tbf *ul_tbf() const {return m_ul_tbf;}</span><br><span style="color: hsl(0, 100%, 40%);">-   gprs_rlcmac_dl_tbf *dl_tbf() const {return m_dl_tbf;}</span><br><span style="color: hsl(0, 100%, 40%);">-   gprs_rlcmac_tbf *tbf(enum gprs_rlcmac_tbf_direction dir) const;</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t tlli() const;</span><br><span style="color: hsl(0, 100%, 40%);">-  void set_tlli(uint32_t tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-   bool confirm_tlli(uint32_t tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-       bool check_tlli(uint32_t tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- void reset();</span><br><span style="color: hsl(0, 100%, 40%);">-   enum mcs_kind mode() const;</span><br><span style="color: hsl(0, 100%, 40%);">-     void set_mode(enum mcs_kind mode);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      const char *imsi() const;</span><br><span style="color: hsl(0, 100%, 40%);">-       void set_imsi(const char *imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t ta() const;</span><br><span style="color: hsl(0, 100%, 40%);">-     void set_ta(uint8_t ta);</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t ms_class() const;</span><br><span style="color: hsl(0, 100%, 40%);">-       uint8_t egprs_ms_class() const;</span><br><span style="color: hsl(0, 100%, 40%);">- void set_ms_class(uint8_t ms_class);</span><br><span style="color: hsl(0, 100%, 40%);">-    void set_egprs_ms_class(uint8_t ms_class);</span><br><span style="color: hsl(0, 100%, 40%);">-      void set_current_cs_dl(enum CodingScheme scheme);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       enum CodingScheme current_cs_ul() const;</span><br><span style="color: hsl(0, 100%, 40%);">-        enum CodingScheme current_cs_dl() const;</span><br><span style="color: hsl(0, 100%, 40%);">-        enum CodingScheme max_cs_ul() const;</span><br><span style="color: hsl(0, 100%, 40%);">-    enum CodingScheme max_cs_dl() const;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    int first_common_ts() const;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t dl_slots() const;</span><br><span style="color: hsl(0, 100%, 40%);">-       uint8_t ul_slots() const;</span><br><span style="color: hsl(0, 100%, 40%);">-       uint8_t reserved_dl_slots() const;</span><br><span style="color: hsl(0, 100%, 40%);">-      uint8_t reserved_ul_slots() const;</span><br><span style="color: hsl(0, 100%, 40%);">-      uint8_t current_pacch_slots() const;</span><br><span style="color: hsl(0, 100%, 40%);">-    gprs_rlcmac_trx *current_trx() const;</span><br><span style="color: hsl(0, 100%, 40%);">-   void set_reserved_slots(gprs_rlcmac_trx *trx,</span><br><span style="color: hsl(0, 100%, 40%);">-           uint8_t ul_slots, uint8_t dl_slots);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    gprs_llc_queue *llc_queue();</span><br><span style="color: hsl(0, 100%, 40%);">-    const gprs_llc_queue *llc_queue() const;</span><br><span style="color: hsl(0, 100%, 40%);">-        gprs_codel *codel_state() const;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        void set_timeout(unsigned secs);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        void attach_tbf(gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-  void attach_ul_tbf(gprs_rlcmac_ul_tbf *tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-    void attach_dl_tbf(gprs_rlcmac_dl_tbf *tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    void detach_tbf(gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  void update_error_rate(gprs_rlcmac_tbf *tbf, int percent);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      bool is_idle() const;</span><br><span style="color: hsl(0, 100%, 40%);">-   bool need_dl_tbf() const;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       void* operator new(size_t num);</span><br><span style="color: hsl(0, 100%, 40%);">- void operator delete(void* p);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  LListHead<GprsMs>& list() {return this->m_list;}</span><br><span style="color: hsl(0, 100%, 40%);">-   const LListHead<GprsMs>& list() const {return this->m_list;}</span><br><span style="color: hsl(0, 100%, 40%);">-       const LListHead<gprs_rlcmac_tbf>& old_tbfs() const {return m_old_tbfs;}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       void update_l1_meas(const pcu_l1_meas *meas);</span><br><span style="color: hsl(0, 100%, 40%);">-   const pcu_l1_meas* l1_meas() const {return &m_l1_meas;};</span><br><span style="color: hsl(0, 100%, 40%);">-    unsigned nack_rate_dl() const;</span><br><span style="color: hsl(0, 100%, 40%);">-  unsigned dl_ctrl_msg() const;</span><br><span style="color: hsl(0, 100%, 40%);">-   void update_dl_ctrl_msg();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* internal use */</span><br><span style="color: hsl(0, 100%, 40%);">-      static void timeout(void *priv_);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       bool app_info_pending;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-protected:</span><br><span style="color: hsl(0, 100%, 40%);">-        void merge_old_ms(GprsMs *old_ms);</span><br><span style="color: hsl(0, 100%, 40%);">-      void update_status();</span><br><span style="color: hsl(0, 100%, 40%);">-   GprsMs *ref();</span><br><span style="color: hsl(0, 100%, 40%);">-  void unref();</span><br><span style="color: hsl(0, 100%, 40%);">-   void start_timer();</span><br><span style="color: hsl(0, 100%, 40%);">-     void stop_timer();</span><br><span style="color: hsl(0, 100%, 40%);">-      void update_cs_ul(const pcu_l1_meas*);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-private:</span><br><span style="color: hsl(0, 100%, 40%);">-  BTS *m_bts;</span><br><span style="color: hsl(0, 100%, 40%);">-     Callback * m_cb;</span><br><span style="color: hsl(0, 100%, 40%);">-        gprs_rlcmac_ul_tbf *m_ul_tbf;</span><br><span style="color: hsl(0, 100%, 40%);">-   gprs_rlcmac_dl_tbf *m_dl_tbf;</span><br><span style="color: hsl(0, 100%, 40%);">-   LListHead<gprs_rlcmac_tbf> m_old_tbfs;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    uint32_t m_tlli;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint32_t m_new_ul_tlli;</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t m_new_dl_tlli;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* store IMSI for look-up and PCH retransmission */</span><br><span style="color: hsl(0, 100%, 40%);">-     char m_imsi[OSMO_IMSI_BUF_SIZE];</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t m_ta;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t m_ms_class;</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t m_egprs_ms_class;</span><br><span style="color: hsl(0, 100%, 40%);">-       /* current coding scheme */</span><br><span style="color: hsl(0, 100%, 40%);">-     enum CodingScheme m_current_cs_ul;</span><br><span style="color: hsl(0, 100%, 40%);">-      enum CodingScheme m_current_cs_dl;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      gprs_llc_queue m_llc_queue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     bool m_is_idle;</span><br><span style="color: hsl(0, 100%, 40%);">- int m_ref;</span><br><span style="color: hsl(0, 100%, 40%);">-      LListHead<GprsMs> m_list;</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_timer_list m_timer;</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned m_delay;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       int64_t m_last_cs_not_low;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      pcu_l1_meas m_l1_meas;</span><br><span style="color: hsl(0, 100%, 40%);">-  unsigned m_nack_rate_dl;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t m_reserved_dl_slots;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t m_reserved_ul_slots;</span><br><span style="color: hsl(0, 100%, 40%);">-    gprs_rlcmac_trx *m_current_trx;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_codel *m_codel_state;</span><br><span style="color: hsl(0, 100%, 40%);">-       enum mcs_kind m_mode;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   unsigned m_dl_ctrl_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gpr_ms_callback {</span><br><span style="color: hsl(120, 100%, 40%);">+     void (*ms_idle)(struct GprsMs *);</span><br><span style="color: hsl(120, 100%, 40%);">+     void (*ms_active)(struct GprsMs *);</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline bool GprsMs::is_idle() const</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head list; /* list of all GprsMs */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gpr_ms_callback cb;</span><br><span style="color: hsl(120, 100%, 40%);">+    bool app_info_pending;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      struct BTS *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_rlcmac_ul_tbf *ul_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_rlcmac_dl_tbf *dl_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head old_tbfs; /* list of gprs_rlcmac_tbf */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t new_ul_tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t new_dl_tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* store IMSI for look-up and PCH retransmission */</span><br><span style="color: hsl(120, 100%, 40%);">+   char imsi[OSMO_IMSI_BUF_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t ta;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t ms_class;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t egprs_ms_class;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* current coding scheme */</span><br><span style="color: hsl(120, 100%, 40%);">+   enum CodingScheme current_cs_ul;</span><br><span style="color: hsl(120, 100%, 40%);">+      enum CodingScheme current_cs_dl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_llc_queue llc_queue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    bool is_idle;</span><br><span style="color: hsl(120, 100%, 40%);">+ int ref;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_timer_list timer;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned delay;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     int64_t last_cs_not_low;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct pcu_l1_meas l1_meas;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned nack_rate_dl;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t reserved_dl_slots;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t reserved_ul_slots;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_rlcmac_trx *current_trx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_codel *codel_state;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum mcs_kind mode;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned dl_ctrl_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs *ms_alloc(struct BTS *bts, uint32_t tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ms_first_common_ts(const struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,</span><br><span style="color: hsl(120, 100%, 40%);">+                    uint8_t ul_slots, uint8_t dl_slots);</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs *ms_ref(struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_unref(struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_ms_class(struct GprsMs *ms, uint8_t ms_class_);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_egprs_ms_class(struct GprsMs *ms, uint8_t ms_class_);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_ta(struct GprsMs *ms, uint8_t ta_);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum CodingScheme ms_current_cs_dl(const struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+enum CodingScheme ms_max_cs_ul(const struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+enum CodingScheme ms_max_cs_dl(const struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_current_cs_dl(struct GprsMs *ms, enum CodingScheme scheme);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_update_error_rate(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, int error_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t ms_current_pacch_slots(const struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_tlli(struct GprsMs *ms, uint32_t tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_imsi(struct GprsMs *ms, const char *imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_tbf *ms_tbf(const struct GprsMs *ms, enum gprs_rlcmac_tbf_direction dir);</span><br><span style="color: hsl(120, 100%, 40%);">+static inline struct gprs_rlcmac_ul_tbf *ms_ul_tbf(const struct GprsMs *ms) {return ms->ul_tbf;}</span><br><span style="color: hsl(120, 100%, 40%);">+static inline struct gprs_rlcmac_dl_tbf *ms_dl_tbf(const struct GprsMs *ms) {return ms->dl_tbf;}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline bool ms_is_idle(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     return !m_ul_tbf && !m_dl_tbf && !m_ref && llist_empty(&m_old_tbfs);</span><br><span style="color: hsl(120, 100%, 40%);">+      return !ms->ul_tbf && !ms->dl_tbf && !ms->ref && llist_empty(&ms->old_tbfs);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline bool GprsMs::need_dl_tbf() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline struct gprs_llc_queue *ms_llc_queue(struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- if (dl_tbf() != NULL && dl_tbf()->state_is_not(GPRS_RLCMAC_WAIT_RELEASE))</span><br><span style="color: hsl(120, 100%, 40%);">+  return &ms->llc_queue;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline bool ms_need_dl_tbf(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ms_dl_tbf(ms) != NULL &&</span><br><span style="color: hsl(120, 100%, 40%);">+      tbf_state((const struct gprs_rlcmac_tbf *)ms_dl_tbf(ms)) != GPRS_RLCMAC_WAIT_RELEASE)</span><br><span>            return false;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       return llc_queue()->size() > 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ return llc_queue_size(ms_llc_queue(ms)) > 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint32_t GprsMs::tlli() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint32_t ms_tlli(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      if (m_new_ul_tlli != GSM_RESERVED_TMSI)</span><br><span style="color: hsl(0, 100%, 40%);">-         return m_new_ul_tlli;</span><br><span style="color: hsl(0, 100%, 40%);">-   if (m_tlli != GSM_RESERVED_TMSI)</span><br><span style="color: hsl(0, 100%, 40%);">-                return m_tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms->new_ul_tlli != GSM_RESERVED_TMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+          return ms->new_ul_tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ms->tlli != GSM_RESERVED_TMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+         return ms->tlli;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- return m_new_dl_tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ms->new_dl_tlli;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline bool GprsMs::check_tlli(uint32_t tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+static inline bool ms_check_tlli(struct GprsMs *ms, uint32_t tlli)</span><br><span> {</span><br><span>    return tlli != GSM_RESERVED_TMSI &&</span><br><span style="color: hsl(0, 100%, 40%);">-             (tlli == m_tlli || tlli == m_new_ul_tlli || tlli == m_new_dl_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+           (tlli == ms->tlli || tlli == ms->new_ul_tlli || tlli == ms->new_dl_tlli);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline const char *GprsMs::imsi() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline const char *ms_imsi(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     return m_imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+        return ms->imsi;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint8_t GprsMs::ta() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint8_t ms_ta(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        return m_ta;</span><br><span style="color: hsl(120, 100%, 40%);">+  return ms->ta;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint8_t GprsMs::ms_class() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint8_t ms_ms_class(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      return m_ms_class;</span><br><span style="color: hsl(120, 100%, 40%);">+    return ms->ms_class;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint8_t GprsMs::egprs_ms_class() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint8_t ms_egprs_ms_class(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    return m_egprs_ms_class;</span><br><span style="color: hsl(120, 100%, 40%);">+      return ms->egprs_ms_class;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline enum CodingScheme GprsMs::current_cs_ul() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline enum CodingScheme ms_current_cs_ul(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    return m_current_cs_ul;</span><br><span style="color: hsl(120, 100%, 40%);">+       return ms->current_cs_ul;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline enum mcs_kind GprsMs::mode() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline enum mcs_kind ms_mode(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       return m_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+        return ms->mode;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline void GprsMs::set_timeout(unsigned secs)</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void ms_set_timeout(struct GprsMs *ms, unsigned secs)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    m_delay = secs;</span><br><span style="color: hsl(120, 100%, 40%);">+       ms->delay = secs;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline gprs_llc_queue *GprsMs::llc_queue()</span><br><span style="color: hsl(120, 100%, 40%);">+static inline struct gprs_codel *ms_codel_state(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  return &m_llc_queue;</span><br><span style="color: hsl(120, 100%, 40%);">+      return ms->codel_state;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline const gprs_llc_queue *GprsMs::llc_queue() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline unsigned ms_nack_rate_dl(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return &m_llc_queue;</span><br><span style="color: hsl(120, 100%, 40%);">+      return ms->nack_rate_dl;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline gprs_codel *GprsMs::codel_state() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline unsigned ms_dl_ctrl_msg(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return m_codel_state;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ms->dl_ctrl_msg;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline unsigned GprsMs::nack_rate_dl() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void ms_update_dl_ctrl_msg(struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       return m_nack_rate_dl;</span><br><span style="color: hsl(120, 100%, 40%);">+        ms->dl_ctrl_msg++;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline unsigned GprsMs::dl_ctrl_msg() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint8_t ms_reserved_dl_slots(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     return m_dl_ctrl_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ms->reserved_dl_slots;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline void GprsMs::update_dl_ctrl_msg()</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint8_t ms_reserved_ul_slots(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     m_dl_ctrl_msg++;</span><br><span style="color: hsl(120, 100%, 40%);">+      return ms->reserved_ul_slots;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint8_t GprsMs::reserved_dl_slots() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline struct gprs_rlcmac_trx *ms_current_trx(const struct GprsMs *ms)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   return m_reserved_dl_slots;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-inline uint8_t GprsMs::reserved_ul_slots() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   return m_reserved_ul_slots;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-inline gprs_rlcmac_trx *GprsMs::current_trx() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        return m_current_trx;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ms->current_trx;</span><br><span> }</span><br><span> </span><br><span> #define LOGPMS(ms, category, level, fmt, args...) \</span><br><span>   LOGP(category, level, "MS(TLLI=0x%08x, IMSI=%s, TA=%" PRIu8 ", %" PRIu8 "/%" PRIu8 ",%s%s) " fmt, \</span><br><span style="color: hsl(0, 100%, 40%);">-          (ms)->tlli(), (ms)->imsi(), (ms)->ta(), (ms)->ms_class(), (ms)->egprs_ms_class(), \</span><br><span style="color: hsl(0, 100%, 40%);">-      (ms)->ul_tbf() ? " UL": "", \</span><br><span style="color: hsl(0, 100%, 40%);">-            (ms)->dl_tbf() ? " DL": "", \</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_tlli(ms), ms_imsi(ms), ms_ta(ms), ms_ms_class(ms), ms_egprs_ms_class(ms), \</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_ul_tbf(ms) ? " UL": "", \</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_dl_tbf(ms) ? " DL": "", \</span><br><span>             ## args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>diff --git a/src/gprs_ms_storage.cpp b/src/gprs_ms_storage.cpp</span><br><span>index 73570b3..6d5b09e 100644</span><br><span>--- a/src/gprs_ms_storage.cpp</span><br><span>+++ b/src/gprs_ms_storage.cpp</span><br><span>@@ -31,9 +31,29 @@</span><br><span> </span><br><span> #define GPRS_UNDEFINED_IMSI "000"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_storage_ms_idle_cb(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_del(&ms->list);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ms->bts)</span><br><span style="color: hsl(120, 100%, 40%);">+               ms->bts->stat_item_add(STAT_MS_PRESENT, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ms_is_idle(ms))</span><br><span style="color: hsl(120, 100%, 40%);">+           talloc_free(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_storage_ms_active_cb(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Nothing to do */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gpr_ms_callback ms_storage_ms_cb = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .ms_idle = ms_storage_ms_idle_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+     .ms_active = ms_storage_ms_active_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> GprsMsStorage::GprsMsStorage(BTS *bts) :</span><br><span>      m_bts(bts)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+       INIT_LLIST_HEAD(&m_list);</span><br><span> }</span><br><span> </span><br><span> GprsMsStorage::~GprsMsStorage()</span><br><span>@@ -43,40 +63,26 @@</span><br><span> </span><br><span> void GprsMsStorage::cleanup()</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       LListHead<GprsMs> *pos, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct llist_head *pos, *tmp;</span><br><span> </span><br><span>    llist_for_each_safe(pos, tmp, &m_list) {</span><br><span style="color: hsl(0, 100%, 40%);">-            GprsMs *ms = pos->entry();</span><br><span style="color: hsl(0, 100%, 40%);">-           ms->set_callback(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-              ms_idle(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+          struct GprsMs *ms = llist_entry(pos, typeof(*ms), list);</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_set_callback(ms, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms_storage_ms_idle_cb(ms);</span><br><span>   }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMsStorage::ms_idle(class GprsMs *ms)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        llist_del(&ms->list());</span><br><span style="color: hsl(0, 100%, 40%);">-  if (m_bts)</span><br><span style="color: hsl(0, 100%, 40%);">-              m_bts->stat_item_add(STAT_MS_PRESENT, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (ms->is_idle())</span><br><span style="color: hsl(0, 100%, 40%);">-           delete ms;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void GprsMsStorage::ms_active(class GprsMs *ms)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     /* Nothing to do */</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> GprsMs *GprsMsStorage::get_ms(uint32_t tlli, uint32_t old_tlli, const char *imsi) const</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llist_head *tmp;</span><br><span>      GprsMs *ms;</span><br><span style="color: hsl(0, 100%, 40%);">-     LListHead<GprsMs> *pos;</span><br><span> </span><br><span>    if (tlli != GSM_RESERVED_TMSI || old_tlli != GSM_RESERVED_TMSI) {</span><br><span style="color: hsl(0, 100%, 40%);">-               llist_for_each(pos, &m_list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      ms = pos->entry();</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (ms->check_tlli(tlli))</span><br><span style="color: hsl(120, 100%, 40%);">+          llist_for_each(tmp, &m_list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms = llist_entry(tmp, typeof(*ms), list);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (ms_check_tlli(ms, tlli))</span><br><span>                                 return ms;</span><br><span style="color: hsl(0, 100%, 40%);">-                      if (ms->check_tlli(old_tlli))</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (ms_check_tlli(ms, old_tlli))</span><br><span>                             return ms;</span><br><span>           }</span><br><span>    }</span><br><span>@@ -84,9 +90,9 @@</span><br><span>        /* not found by TLLI */</span><br><span> </span><br><span>  if (imsi && imsi[0] && strcmp(imsi, GPRS_UNDEFINED_IMSI) != 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                llist_for_each(pos, &m_list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      ms = pos->entry();</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (strcmp(imsi, ms->imsi()) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+         llist_for_each(tmp, &m_list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms = llist_entry(tmp, typeof(*ms), list);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (strcmp(imsi, ms_imsi(ms)) == 0)</span><br><span>                          return ms;</span><br><span>           }</span><br><span>    }</span><br><span>@@ -98,10 +104,10 @@</span><br><span> {</span><br><span>        GprsMs *ms;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms = new GprsMs(m_bts, GSM_RESERVED_TMSI);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms = ms_alloc(m_bts, GSM_RESERVED_TMSI);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_callback(this);</span><br><span style="color: hsl(0, 100%, 40%);">-      llist_add(&ms->list(), &m_list);</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_set_callback(ms, &ms_storage_ms_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_add(&ms->list, &m_list);</span><br><span>    if (m_bts)</span><br><span>           m_bts->stat_item_add(STAT_MS_PRESENT, 1);</span><br><span> </span><br><span>diff --git a/src/gprs_ms_storage.h b/src/gprs_ms_storage.h</span><br><span>index 35062f3..af49688 100644</span><br><span>--- a/src/gprs_ms_storage.h</span><br><span>+++ b/src/gprs_ms_storage.h</span><br><span>@@ -21,28 +21,24 @@</span><br><span> #pragma once</span><br><span> </span><br><span> #include "gprs_ms.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "cxx_linuxlist.h"</span><br><span> #include "tbf.h"</span><br><span> #include <stdint.h></span><br><span> #include <stddef.h></span><br><span> </span><br><span> struct BTS;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-class GprsMsStorage : public GprsMs::Callback {</span><br><span style="color: hsl(120, 100%, 40%);">+class GprsMsStorage {</span><br><span> public:</span><br><span>    GprsMsStorage(BTS *bts);</span><br><span>     ~GprsMsStorage();</span><br><span> </span><br><span>        void cleanup();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     virtual void ms_idle(class GprsMs *);</span><br><span style="color: hsl(0, 100%, 40%);">-   virtual void ms_active(class GprsMs *);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>      GprsMs *get_ms(uint32_t tlli, uint32_t old_tlli = GSM_RESERVED_TMSI, const char *imsi = NULL) const;</span><br><span>         GprsMs *create_ms();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        const LListHead<GprsMs>& ms_list() const {return m_list;}</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct llist_head* ms_list() const {return &m_list;}</span><br><span> private:</span><br><span>   BTS *m_bts;</span><br><span style="color: hsl(0, 100%, 40%);">-     LListHead<GprsMs> m_list;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head m_list; /* list of struct GprsMs */</span><br><span> };</span><br><span>diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp</span><br><span>index 70d8237..caf121f 100644</span><br><span>--- a/src/gprs_rlcmac_sched.cpp</span><br><span>+++ b/src/gprs_rlcmac_sched.cpp</span><br><span>@@ -234,7 +234,7 @@</span><br><span>                   "message at RTS for %s (TRX=%d, TS=%d)\n",</span><br><span>                         tbf_name(tbf), trx, ts);</span><br><span>             /* Updates the dl ctrl msg counter for ms */</span><br><span style="color: hsl(0, 100%, 40%);">-            tbf->ms()->update_dl_ctrl_msg();</span><br><span style="color: hsl(120, 100%, 40%);">+                ms_update_dl_ctrl_msg(tbf->ms());</span><br><span>                 return msg;</span><br><span>  }</span><br><span> </span><br><span>@@ -342,7 +342,7 @@</span><br><span>          pdch->next_dl_tfi = (prio_tfi + 1) & 31;</span><br><span>              /* generate DL data block */</span><br><span>                 msg = prio_tbf->create_dl_acked_block(fn, ts, req_mcs_kind);</span><br><span style="color: hsl(0, 100%, 40%);">-         *is_egprs = prio_tbf->ms()->mode() != GPRS;</span><br><span style="color: hsl(120, 100%, 40%);">+             *is_egprs = ms_mode(prio_tbf->ms()) != GPRS;</span><br><span>      }</span><br><span> </span><br><span>        return msg;</span><br><span>@@ -463,7 +463,7 @@</span><br><span>                     * only be able to read USF if dl block uses GMSK</span><br><span>                     * (CS1-4, MCS1-4)</span><br><span>                    */</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (req_mcs_kind == EGPRS && usf_tbf->ms()->mode() != EGPRS)</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (req_mcs_kind == EGPRS && ms_mode(usf_tbf->ms()) != EGPRS)</span><br><span>                             req_mcs_kind = EGPRS_GMSK;</span><br><span>           } else {</span><br><span>                     usf = USF_UNUSED;</span><br><span>diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp</span><br><span>index 9551c59..1ef32f2 100644</span><br><span>--- a/src/gprs_rlcmac_ts_alloc.cpp</span><br><span>+++ b/src/gprs_rlcmac_ts_alloc.cpp</span><br><span>@@ -245,8 +245,8 @@</span><br><span>         unsigned ts;</span><br><span> </span><br><span>     /* We must use the TRX currently actively used by an MS */</span><br><span style="color: hsl(0, 100%, 40%);">-      if (ms && ms->current_trx())</span><br><span style="color: hsl(0, 100%, 40%);">-         return ms->current_trx()->trx_no;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ms && ms_current_trx(ms))</span><br><span style="color: hsl(120, 100%, 40%);">+         return ms_current_trx(ms)->trx_no;</span><br><span> </span><br><span>    if (use_trx >= 0 && use_trx < 8)</span><br><span>               return use_trx;</span><br><span>@@ -320,8 +320,8 @@</span><br><span>                use_trx = trx->trx_no;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (use_trx == -1 && ms->current_trx())</span><br><span style="color: hsl(0, 100%, 40%);">-              use_trx = ms->current_trx()->trx_no;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (use_trx == -1 && ms_current_trx(ms))</span><br><span style="color: hsl(120, 100%, 40%);">+              use_trx = ms_current_trx(ms)->trx_no;</span><br><span> </span><br><span>         tfi = bts->tfi_find_free(dir, &trx_no, use_trx);</span><br><span>      if (tfi < 0)</span><br><span>@@ -357,7 +357,7 @@</span><br><span>        const char *mask_reason = NULL;</span><br><span>      const GprsMs *ms = ms_;</span><br><span>      const gprs_rlcmac_tbf *tbf = tbf_;</span><br><span style="color: hsl(0, 100%, 40%);">-      gprs_rlcmac_trx *trx = ms->current_trx();</span><br><span style="color: hsl(120, 100%, 40%);">+  gprs_rlcmac_trx *trx = ms_current_trx(ms);</span><br><span> </span><br><span>       LOGPAL(tbf, "A", single, use_trx, LOGL_DEBUG, "Alloc start\n");</span><br><span> </span><br><span>@@ -370,10 +370,10 @@</span><br><span>      if (!trx)</span><br><span>            trx = &bts->trx[trx_no];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     dl_slots = ms->reserved_dl_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-  ul_slots = ms->reserved_ul_slots();</span><br><span style="color: hsl(120, 100%, 40%);">+        dl_slots = ms_reserved_dl_slots(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+  ul_slots = ms_reserved_ul_slots(ms);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        ts = ms->first_common_ts();</span><br><span style="color: hsl(120, 100%, 40%);">+        ts = ms_first_common_ts(ms);</span><br><span> </span><br><span>     if (ts >= 0) {</span><br><span>            mask_reason = "need to reuse TS";</span><br><span>@@ -420,7 +420,7 @@</span><br><span>    tbf_->trx = trx;</span><br><span>  /* the only one TS is the common TS */</span><br><span>       tbf_->first_ts = tbf_->first_common_ts = ts;</span><br><span style="color: hsl(0, 100%, 40%);">-      ms_->set_reserved_slots(trx, 1 << ts, 1 << ts);</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_set_reserved_slots(ms_, trx, 1 << ts, 1 << ts);</span><br><span> </span><br><span>   tbf_->upgrade_to_multislot = 0;</span><br><span>   bts->bts->do_rate_ctr_inc(CTR_TBF_ALLOC_ALGO_A);</span><br><span>@@ -774,11 +774,11 @@</span><br><span> {</span><br><span>  char slot_info[9] = { 0 };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  if (res_ul_slots == ms->reserved_ul_slots() && res_dl_slots == ms->reserved_dl_slots())</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res_ul_slots == ms_reserved_ul_slots(ms) && res_dl_slots == ms_reserved_dl_slots(ms))</span><br><span>            return;</span><br><span> </span><br><span>  /* The reserved slots have changed, update the MS */</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_reserved_slots(trx, res_ul_slots, res_dl_slots);</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_set_reserved_slots(ms, trx, res_ul_slots, res_dl_slots);</span><br><span> </span><br><span>      ts_format(slot_info, dl_slots, ul_slots);</span><br><span>    LOGP(DRLCMAC, LOGL_DEBUG, "- Reserved DL/UL slots: (TS=0)\"%s\"(TS=7)\n", slot_info);</span><br><span>@@ -867,10 +867,10 @@</span><br><span>            return -EINVAL;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   dl_slots = ms->reserved_dl_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-  ul_slots = ms->reserved_ul_slots();</span><br><span style="color: hsl(0, 100%, 40%);">-  first_common_ts = ms->first_common_ts();</span><br><span style="color: hsl(0, 100%, 40%);">-     trx = ms->current_trx();</span><br><span style="color: hsl(120, 100%, 40%);">+   dl_slots = ms_reserved_dl_slots(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+  ul_slots = ms_reserved_ul_slots(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+  first_common_ts = ms_first_common_ts(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+     trx = ms_current_trx(ms);</span><br><span> </span><br><span>        /* Step 2a: Find usable TRX and TFI */</span><br><span>       tfi = tfi_find_free(bts->bts, trx, ms, tbf->direction, use_trx, &trx_no);</span><br><span>@@ -884,7 +884,7 @@</span><br><span>            trx = &bts->trx[trx_no];</span><br><span> </span><br><span>  if (!dl_slots || !ul_slots) {</span><br><span style="color: hsl(0, 100%, 40%);">-           rc = find_multi_slots(trx, ms->ms_class(), &ul_slots, &dl_slots);</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = find_multi_slots(trx, ms_ms_class(ms), &ul_slots, &dl_slots);</span><br><span>           if (rc < 0)</span><br><span>                       return rc;</span><br><span>   }</span><br><span>diff --git a/src/llc.cpp b/src/llc.cpp</span><br><span>index e2d01c2..d1122f5 100644</span><br><span>--- a/src/llc.cpp</span><br><span>+++ b/src/llc.cpp</span><br><span>@@ -97,12 +97,12 @@</span><br><span>     return true;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void gprs_llc_queue::init()</span><br><span style="color: hsl(120, 100%, 40%);">+void llc_queue_init(struct gprs_llc_queue *q)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    INIT_LLIST_HEAD(&m_queue);</span><br><span style="color: hsl(0, 100%, 40%);">-  m_queue_size = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       m_queue_octets = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     m_avg_queue_delay = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        INIT_LLIST_HEAD(&q->m_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+  q->m_queue_size = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       q->m_queue_octets = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     q->m_avg_queue_delay = 0;</span><br><span> }</span><br><span> </span><br><span> </span><br><span>@@ -122,21 +122,21 @@</span><br><span>    msgb_enqueue(&m_queue, llc_msg);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void gprs_llc_queue::clear(BTS *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+void llc_queue_clear(struct gprs_llc_queue *q, struct BTS *bts)</span><br><span> {</span><br><span>      struct msgb *msg;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   while ((msg = msgb_dequeue(&m_queue))) {</span><br><span style="color: hsl(120, 100%, 40%);">+  while ((msg = msgb_dequeue(&q->m_queue))) {</span><br><span>           if (bts)</span><br><span>                     bts->do_rate_ctr_inc(CTR_LLC_FRAME_DROPPED);</span><br><span>              msgb_free(msg);</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   m_queue_size = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       m_queue_octets = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   q->m_queue_size = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       q->m_queue_octets = 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void gprs_llc_queue::move_and_merge(gprs_llc_queue *o)</span><br><span style="color: hsl(120, 100%, 40%);">+void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o)</span><br><span> {</span><br><span>     struct msgb *msg, *msg1 = NULL, *msg2 = NULL;</span><br><span>        struct llist_head new_queue;</span><br><span>@@ -146,7 +146,7 @@</span><br><span> </span><br><span>       while (1) {</span><br><span>          if (msg1 == NULL)</span><br><span style="color: hsl(0, 100%, 40%);">-                       msg1 = msgb_dequeue(&m_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+                    msg1 = msgb_dequeue(&q->m_queue);</span><br><span> </span><br><span>                 if (msg2 == NULL)</span><br><span>                    msg2 = msgb_dequeue(&o->m_queue);</span><br><span>@@ -178,15 +178,15 @@</span><br><span>             queue_octets += msgb_length(msg);</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(llist_empty(&m_queue));</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(llist_empty(&q->m_queue));</span><br><span>        OSMO_ASSERT(llist_empty(&o->m_queue));</span><br><span> </span><br><span>    o->m_queue_size = 0;</span><br><span>      o->m_queue_octets = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   llist_splice_init(&new_queue, &m_queue);</span><br><span style="color: hsl(0, 100%, 40%);">-        m_queue_size = queue_size;</span><br><span style="color: hsl(0, 100%, 40%);">-      m_queue_octets = queue_octets;</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_splice_init(&new_queue, &q->m_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+        q->m_queue_size = queue_size;</span><br><span style="color: hsl(120, 100%, 40%);">+      q->m_queue_octets = queue_octets;</span><br><span> }</span><br><span> </span><br><span> #define ALPHA 0.5f</span><br><span>diff --git a/src/llc.h b/src/llc.h</span><br><span>index 3c2e57a..72fa62e 100644</span><br><span>--- a/src/llc.h</span><br><span>+++ b/src/llc.h</span><br><span>@@ -18,9 +18,13 @@</span><br><span> </span><br><span> #pragma once</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>      #include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span> #include <stdint.h></span><br><span> #include <string.h></span><br><span>@@ -34,6 +38,8 @@</span><br><span>  * I represent the LLC data to a MS</span><br><span>  */</span><br><span> struct gprs_llc {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span>        static bool is_user_data_frame(uint8_t *data, size_t len);</span><br><span> </span><br><span>       void init();</span><br><span>@@ -43,92 +49,86 @@</span><br><span>   void put_frame(const uint8_t *data, size_t len);</span><br><span>     void put_dummy_frame(size_t req_len);</span><br><span>        void append_frame(const uint8_t *data, size_t len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     void consume(size_t len);</span><br><span style="color: hsl(0, 100%, 40%);">-       void consume(uint8_t *data, size_t len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        uint16_t chunk_size() const;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint16_t remaining_space() const;</span><br><span style="color: hsl(0, 100%, 40%);">-       uint16_t frame_length() const;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  bool fits_in_current_frame(uint8_t size) const;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span>  uint8_t frame[LLC_MAX_LEN]; /* current DL or UL frame */</span><br><span>     uint16_t m_index; /* current write/read position of frame */</span><br><span>         uint16_t m_length; /* len of current DL LLC_frame, 0 == no frame */</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct MetaInfo {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct timespec recv_time;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct timespec expire_time;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span> /**</span><br><span>  * I store the LLC frames that come from the SGSN.</span><br><span>  */</span><br><span> struct gprs_llc_queue {</span><br><span style="color: hsl(0, 100%, 40%);">- struct MetaInfo {</span><br><span style="color: hsl(0, 100%, 40%);">-               struct timespec recv_time;</span><br><span style="color: hsl(0, 100%, 40%);">-              struct timespec expire_time;</span><br><span style="color: hsl(0, 100%, 40%);">-    };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span>       static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec,</span><br><span>               struct timespec *tv);</span><br><span>        static bool is_frame_expired(const struct timespec *now,</span><br><span>             const struct timespec *tv);</span><br><span>  static bool is_user_data_frame(uint8_t *data, size_t len);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  void init();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         void enqueue(struct msgb *llc_msg, const struct timespec *expire_time);</span><br><span>      struct msgb *dequeue(const MetaInfo **info = 0);</span><br><span style="color: hsl(0, 100%, 40%);">-        void clear(BTS *bts);</span><br><span style="color: hsl(0, 100%, 40%);">-   void move_and_merge(gprs_llc_queue *o);</span><br><span style="color: hsl(0, 100%, 40%);">- size_t size() const;</span><br><span style="color: hsl(0, 100%, 40%);">-    size_t octets() const;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-private:</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>       uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */</span><br><span>      size_t m_queue_size;</span><br><span>         size_t m_queue_octets;</span><br><span>       struct llist_head m_queue; /* queued LLC DL data */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+void llc_queue_init(struct gprs_llc_queue *q);</span><br><span style="color: hsl(120, 100%, 40%);">+void llc_queue_clear(struct gprs_llc_queue *q, struct BTS *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint16_t gprs_llc::chunk_size() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint16_t llc_chunk_size(const struct gprs_llc *llc)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return m_length - m_index;</span><br><span style="color: hsl(120, 100%, 40%);">+    return llc->m_length - llc->m_index;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint16_t gprs_llc::remaining_space() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint16_t llc_remaining_space(const struct gprs_llc *llc)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       return LLC_MAX_LEN - m_length;</span><br><span style="color: hsl(120, 100%, 40%);">+        return LLC_MAX_LEN - llc->m_length;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint16_t gprs_llc::frame_length() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint16_t llc_frame_length(const struct gprs_llc *llc)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return m_length;</span><br><span style="color: hsl(120, 100%, 40%);">+      return llc->m_length;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline void gprs_llc::consume(size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void llc_consume(struct gprs_llc *llc, size_t len)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       m_index += len;</span><br><span style="color: hsl(120, 100%, 40%);">+       llc->m_index += len;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline void gprs_llc::consume(uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void llc_consume_data(struct gprs_llc *llc, uint8_t *data, size_t len)</span><br><span> {</span><br><span>  /* copy and increment index */</span><br><span style="color: hsl(0, 100%, 40%);">-  memcpy(data, frame + m_index, len);</span><br><span style="color: hsl(0, 100%, 40%);">-     consume(len);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(data, llc->frame + llc->m_index, len);</span><br><span style="color: hsl(120, 100%, 40%);">+   llc_consume(llc, len);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline bool gprs_llc::fits_in_current_frame(uint8_t chunk_size) const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline bool llc_fits_in_current_frame(const struct gprs_llc *llc, uint8_t chunk_size)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return m_length + chunk_size <= LLC_MAX_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+       return llc->m_length + chunk_size <= LLC_MAX_LEN;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline size_t gprs_llc_queue::size() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline size_t llc_queue_size(const struct gprs_llc_queue *q)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    return m_queue_size;</span><br><span style="color: hsl(120, 100%, 40%);">+  return q->m_queue_size;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline size_t gprs_llc_queue::octets() const</span><br><span style="color: hsl(120, 100%, 40%);">+static inline size_t llc_queue_octets(const struct gprs_llc_queue *q)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     return m_queue_octets;</span><br><span style="color: hsl(120, 100%, 40%);">+        return q->m_queue_octets;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp</span><br><span>index a984591..9cc6270 100644</span><br><span>--- a/src/pcu_l1_if.cpp</span><br><span>+++ b/src/pcu_l1_if.cpp</span><br><span>@@ -318,7 +318,7 @@</span><br><span>    struct gprs_rlcmac_bts *bts = bts_main_data();</span><br><span>       int rc;</span><br><span>      int current_fn = get_current_fn();</span><br><span style="color: hsl(0, 100%, 40%);">-      pcu_l1_meas meas;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct pcu_l1_meas meas = {0};</span><br><span>       uint8_t gsmtap_chantype;</span><br><span> </span><br><span>         LOGP(DL1IF, LOGL_DEBUG, "Data indication received: sapi=%d arfcn=%d "</span><br><span>@@ -328,11 +328,11 @@</span><br><span> </span><br><span>  switch (data_ind->sapi) {</span><br><span>         case PCU_IF_SAPI_PDTCH:</span><br><span style="color: hsl(0, 100%, 40%);">-         meas.set_rssi(data_ind->rssi);</span><br><span style="color: hsl(120, 100%, 40%);">+             pcu_l1_meas_set_rssi(&meas, data_ind->rssi);</span><br><span>          /* convert BER to % value */</span><br><span style="color: hsl(0, 100%, 40%);">-            meas.set_ber(data_ind->ber10k / 100);</span><br><span style="color: hsl(0, 100%, 40%);">-                meas.set_bto(data_ind->ta_offs_qbits);</span><br><span style="color: hsl(0, 100%, 40%);">-               meas.set_link_qual(data_ind->lqual_cb / 10);</span><br><span style="color: hsl(120, 100%, 40%);">+               pcu_l1_meas_set_ber(&meas, data_ind->ber10k / 100);</span><br><span style="color: hsl(120, 100%, 40%);">+            pcu_l1_meas_set_bto(&meas, data_ind->ta_offs_qbits);</span><br><span style="color: hsl(120, 100%, 40%);">+           pcu_l1_meas_set_link_qual(&meas, data_ind->lqual_cb / 10);</span><br><span> </span><br><span>                LOGP(DL1IF, LOGL_DEBUG, "Data indication with raw measurements received: BER10k = %d, BTO = %d, Q = %d\n",</span><br><span>                      data_ind->ber10k, data_ind->ta_offs_qbits, data_ind->lqual_cb);</span><br><span>@@ -824,8 +824,8 @@</span><br><span>  if ((ms = bts->ms_store().get_ms(susp_req->tlli))) {</span><br><span>           /* We need to catch both pointers here since MS may become freed</span><br><span>                after first tbf_free(dl_tbf) if only DL TBF was available */</span><br><span style="color: hsl(0, 100%, 40%);">-         dl_tbf = ms->dl_tbf();</span><br><span style="color: hsl(0, 100%, 40%);">-               ul_tbf = ms->ul_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+             dl_tbf = ms_dl_tbf(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+               ul_tbf = ms_ul_tbf(ms);</span><br><span>              if (dl_tbf)</span><br><span>                  tbf_free(dl_tbf);</span><br><span>            if (ul_tbf)</span><br><span>@@ -840,7 +840,7 @@</span><br><span> </span><br><span> static int pcu_rx_app_info_req(struct gsm_pcu_if_app_info_req *app_info_req)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      LListHead<GprsMs> *ms_iter;</span><br><span style="color: hsl(120, 100%, 40%);">+     GprsMs *ms;</span><br><span>  BTS *bts = BTS::main_bts();</span><br><span>  struct gprs_rlcmac_bts *bts_data = bts->bts_data();</span><br><span> </span><br><span>@@ -848,9 +848,8 @@</span><br><span>          app_info_req->application_type, app_info_req->len);</span><br><span> </span><br><span>   bts_data->app_info_pending = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-      llist_for_each(ms_iter, &bts->ms_store().ms_list()) {</span><br><span style="color: hsl(0, 100%, 40%);">-            GprsMs *ms = ms_iter->entry();</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!ms->dl_tbf())</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(ms, bts->ms_store().ms_list(), list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!ms_dl_tbf(ms))</span><br><span>                  continue;</span><br><span>            bts_data->app_info_pending++;</span><br><span>             ms->app_info_pending = true;</span><br><span>diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h</span><br><span>index f86e708..65fea9c 100644</span><br><span>--- a/src/pcu_l1_if.h</span><br><span>+++ b/src/pcu_l1_if.h</span><br><span>@@ -79,19 +79,13 @@</span><br><span>       unsigned have_ms_i_level:1;</span><br><span> </span><br><span>      int16_t ms_i_level; /* I_LEVEL in dB */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef __cplusplus</span><br><span style="color: hsl(0, 100%, 40%);">-       pcu_l1_meas_ts& set_ms_i_level(int16_t v) {</span><br><span style="color: hsl(0, 100%, 40%);">-         ms_i_level = v; have_ms_i_level = 1; return *this;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       pcu_l1_meas_ts() :</span><br><span style="color: hsl(0, 100%, 40%);">-              have_ms_i_level(0),</span><br><span style="color: hsl(0, 100%, 40%);">-             ms_i_level(0)</span><br><span style="color: hsl(0, 100%, 40%);">-   {}</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_ts_set_ms_i_level(struct pcu_l1_meas_ts* ts, int16_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+  ts->ms_i_level = v;</span><br><span style="color: hsl(120, 100%, 40%);">+        ts->have_ms_i_level = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct pcu_l1_meas {</span><br><span>     unsigned have_rssi:1;</span><br><span>        unsigned have_ber:1;</span><br><span>@@ -111,48 +105,43 @@</span><br><span>         int16_t ms_sign_var; /* SIGN_VAR in dB */</span><br><span> </span><br><span>        struct pcu_l1_meas_ts ts[8];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef __cplusplus</span><br><span style="color: hsl(0, 100%, 40%);">-  pcu_l1_meas& set_rssi(int8_t v) { rssi = v; have_rssi = 1; return *this;}</span><br><span style="color: hsl(0, 100%, 40%);">-   pcu_l1_meas& set_ber(uint8_t v) { ber = v; have_ber = 1; return *this;}</span><br><span style="color: hsl(0, 100%, 40%);">-     pcu_l1_meas& set_bto(int16_t v) { bto = v; have_bto = 1; return *this;}</span><br><span style="color: hsl(0, 100%, 40%);">-     pcu_l1_meas& set_link_qual(int16_t v) {</span><br><span style="color: hsl(0, 100%, 40%);">-             link_qual = v; have_link_qual = 1; return *this;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       pcu_l1_meas& set_ms_rx_qual(int16_t v) {</span><br><span style="color: hsl(0, 100%, 40%);">-            ms_rx_qual = v; have_ms_rx_qual = 1; return *this;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       pcu_l1_meas& set_ms_c_value(int16_t v) {</span><br><span style="color: hsl(0, 100%, 40%);">-            ms_c_value = v; have_ms_c_value = 1; return *this;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       pcu_l1_meas& set_ms_sign_var(int16_t v) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ms_sign_var = v; have_ms_sign_var = 1; return *this;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-       pcu_l1_meas& set_ms_i_level(size_t idx, int16_t v) {</span><br><span style="color: hsl(0, 100%, 40%);">-                ts[idx].set_ms_i_level(v); have_ms_i_level = 1; return *this;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-       pcu_l1_meas() :</span><br><span style="color: hsl(0, 100%, 40%);">-         have_rssi(0),</span><br><span style="color: hsl(0, 100%, 40%);">-           have_ber(0),</span><br><span style="color: hsl(0, 100%, 40%);">-            have_bto(0),</span><br><span style="color: hsl(0, 100%, 40%);">-            have_link_qual(0),</span><br><span style="color: hsl(0, 100%, 40%);">-              have_ms_rx_qual(0),</span><br><span style="color: hsl(0, 100%, 40%);">-             have_ms_c_value(0),</span><br><span style="color: hsl(0, 100%, 40%);">-             have_ms_sign_var(0),</span><br><span style="color: hsl(0, 100%, 40%);">-            have_ms_i_level(0),</span><br><span style="color: hsl(0, 100%, 40%);">-             rssi(0),</span><br><span style="color: hsl(0, 100%, 40%);">-                ber(0),</span><br><span style="color: hsl(0, 100%, 40%);">-         bto(0),</span><br><span style="color: hsl(0, 100%, 40%);">-         link_qual(0),</span><br><span style="color: hsl(0, 100%, 40%);">-           ms_rx_qual(0),</span><br><span style="color: hsl(0, 100%, 40%);">-          ms_c_value(0),</span><br><span style="color: hsl(0, 100%, 40%);">-          ms_sign_var(0)</span><br><span style="color: hsl(0, 100%, 40%);">-  {}</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_set_rssi(struct pcu_l1_meas *m, int8_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+        m->rssi = v;</span><br><span style="color: hsl(120, 100%, 40%);">+       m->have_rssi = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_set_ber(struct pcu_l1_meas *m, uint8_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+   m->ber = v;</span><br><span style="color: hsl(120, 100%, 40%);">+        m->have_ber = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_set_bto(struct pcu_l1_meas *m, int16_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+    m->bto = v;</span><br><span style="color: hsl(120, 100%, 40%);">+        m->have_bto = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_set_link_qual(struct pcu_l1_meas *m, int16_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+      m->link_qual = v;</span><br><span style="color: hsl(120, 100%, 40%);">+  m->have_link_qual = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_set_ms_rx_qual(struct pcu_l1_meas *m, int16_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+       m->ms_rx_qual = v;</span><br><span style="color: hsl(120, 100%, 40%);">+ m->have_ms_rx_qual = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_set_ms_c_value(struct pcu_l1_meas *m, int16_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+      m->ms_c_value = v;</span><br><span style="color: hsl(120, 100%, 40%);">+ m->have_ms_c_value = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_set_ms_sign_var(struct pcu_l1_meas *m, int16_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+     m->ms_sign_var = v;</span><br><span style="color: hsl(120, 100%, 40%);">+        m->have_ms_sign_var = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void pcu_l1_meas_set_ms_i_level(struct pcu_l1_meas *m, size_t idx, int16_t v) {</span><br><span style="color: hsl(120, 100%, 40%);">+ pcu_l1_meas_ts_set_ms_i_level(&m->ts[idx], v);</span><br><span style="color: hsl(120, 100%, 40%);">+ m->have_ms_i_level = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef __cplusplus</span><br><span style="color: hsl(0, 100%, 40%);">-void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, </span><br><span style="color: hsl(120, 100%, 40%);">+void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,</span><br><span>         uint32_t fn, uint8_t block_nr);</span><br><span> void pcu_l1if_tx_ptcch(uint8_t trx, uint8_t ts, uint16_t arfcn,</span><br><span>                  uint32_t fn, uint8_t block_nr,</span><br><span>diff --git a/src/pcu_utils.h b/src/pcu_utils.h</span><br><span>index 8196a93..cb2fd91 100644</span><br><span>--- a/src/pcu_utils.h</span><br><span>+++ b/src/pcu_utils.h</span><br><span>@@ -15,26 +15,32 @@</span><br><span>  * along with this program; if not, write to the Free Software</span><br><span>  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> #include <osmocom/gsm/gsm_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <time.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline int msecs_to_frames(int msecs) {</span><br><span style="color: hsl(120, 100%, 40%);">+static inline int msecs_to_frames(int msecs) {</span><br><span>    return (msecs * (1024 * 1000 / 4615)) / 1024;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint32_t next_fn(uint32_t fn, uint32_t offset)</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint32_t next_fn(uint32_t fn, uint32_t offset)</span><br><span> {</span><br><span>       return (fn + offset) % GSM_MAX_FN;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline void csecs_to_timespec(unsigned csecs, struct timespec *ts) {</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void csecs_to_timespec(unsigned csecs, struct timespec *ts) {</span><br><span>         ts->tv_sec  = csecs / 100;</span><br><span>        ts->tv_nsec = (csecs % 100) * 10000000;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> template <typename T></span><br><span> inline unsigned int pcu_bitcount(T x)</span><br><span> {</span><br><span>@@ -44,8 +50,15 @@</span><br><span> </span><br><span>        return count;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline uint8_t pcu_lsb(uint8_t x)</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint8_t pcu_lsb(uint8_t x)</span><br><span> {</span><br><span>       return x & -x;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Used to store a C++ class in a llist used by C code */</span><br><span style="color: hsl(120, 100%, 40%);">+struct llist_item {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head list; /* item used by llist */</span><br><span style="color: hsl(120, 100%, 40%);">+      void *entry;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span>diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp</span><br><span>index 416c006..6100b13 100644</span><br><span>--- a/src/pcu_vty_functions.cpp</span><br><span>+++ b/src/pcu_vty_functions.cpp</span><br><span>@@ -61,7 +61,7 @@</span><br><span>                tbf->first_ts,</span><br><span>            tbf->first_common_ts, tbf->control_ts,</span><br><span>                 tbf->ms_class(),</span><br><span style="color: hsl(0, 100%, 40%);">-             tbf->ms() ? tbf->ms()->egprs_ms_class() : -1,</span><br><span style="color: hsl(120, 100%, 40%);">+                tbf->ms() ? ms_egprs_ms_class(tbf->ms()) : -1,</span><br><span>                 VTY_NEWLINE);</span><br><span>        vty_out(vty, " TS_alloc=");</span><br><span>        for (int i = 0; i < 8; i++) {</span><br><span>@@ -79,7 +79,7 @@</span><br><span>                         ul_tbf->window_size(), win->v_q(), win->v_r());</span><br><span>             vty_out(vty, "%s", VTY_NEWLINE);</span><br><span>           vty_out(vty, " TBF Statistics:%s", VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-              if (GPRS == tbf->ms()->mode()) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (GPRS == ms_mode(tbf->ms())) {</span><br><span>                         vty_out_rate_ctr_group(vty, " ", ul_tbf->m_ul_gprs_ctrs);</span><br><span>               } else {</span><br><span>                     vty_out_rate_ctr_group(vty, " ", ul_tbf->m_ul_egprs_ctrs);</span><br><span>@@ -92,7 +92,7 @@</span><br><span>                  win->window_stalled() ? " STALLED" : "");</span><br><span>             vty_out(vty, "%s", VTY_NEWLINE);</span><br><span>           vty_out_rate_ctr_group(vty, " ", tbf->m_ctrs);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (GPRS == tbf->ms()->mode()) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (GPRS == ms_mode(tbf->ms())) {</span><br><span>                         vty_out_rate_ctr_group(vty, " ", dl_tbf->m_dl_gprs_ctrs);</span><br><span>               } else {</span><br><span>                     vty_out_rate_ctr_group(vty, " ", dl_tbf->m_dl_egprs_ctrs);</span><br><span>@@ -124,81 +124,83 @@</span><br><span> static int show_ms(struct vty *vty, GprsMs *ms)</span><br><span> {</span><br><span>      unsigned i;</span><br><span style="color: hsl(0, 100%, 40%);">-     LListHead<gprs_rlcmac_tbf> *i_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_item *i_tbf;</span><br><span>    uint8_t slots;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms->tlli(), ms->imsi(), VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   vty_out(vty, "  Timing advance (TA):    %d%s", ms->ta(), VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-     vty_out(vty, "  Coding scheme uplink:   %s%s", mcs_name(ms->current_cs_ul()),</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms_tlli(ms), ms_imsi(ms), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+     vty_out(vty, "  Timing advance (TA):    %d%s", ms_ta(ms), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+     vty_out(vty, "  Coding scheme uplink:   %s%s", mcs_name(ms_current_cs_ul(ms)),</span><br><span>             VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   vty_out(vty, "  Coding scheme downlink: %s%s", mcs_name(ms->current_cs_dl()),</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, "  Coding scheme downlink: %s%s", mcs_name(ms_current_cs_dl(ms)),</span><br><span>             VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   vty_out(vty, "  Mode:                   %s%s", mode_name(ms->mode()), VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-        vty_out(vty, "  MS class:               %d%s", ms->ms_class(), VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-       vty_out(vty, "  EGPRS MS class:         %d%s", ms->egprs_ms_class(), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+       vty_out(vty, "  Mode:                   %s%s", mode_name(ms_mode(ms)), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+        vty_out(vty, "  MS class:               %d%s", ms_ms_class(ms), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+       vty_out(vty, "  EGPRS MS class:         %d%s", ms_egprs_ms_class(ms), VTY_NEWLINE);</span><br><span>        vty_out(vty, "  PACCH:                  ");</span><br><span style="color: hsl(0, 100%, 40%);">-   slots = ms->current_pacch_slots();</span><br><span style="color: hsl(120, 100%, 40%);">+ slots = ms_current_pacch_slots(ms);</span><br><span>  for (int i = 0; i < 8; i++)</span><br><span>               if (slots & (1 << i))</span><br><span>                      vty_out(vty, "%d ", i);</span><br><span>    vty_out(vty, "%s", VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-      vty_out(vty, "  LLC queue length:       %zd%s", ms->llc_queue()->size(),</span><br><span style="color: hsl(120, 100%, 40%);">+      vty_out(vty, "  LLC queue length:       %zd%s", llc_queue_size(ms_llc_queue(ms)),</span><br><span>          VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   vty_out(vty, "  LLC queue octets:       %zd%s", ms->llc_queue()->octets(),</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, "  LLC queue octets:       %zd%s", llc_queue_octets(ms_llc_queue(ms)),</span><br><span>                VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (ms->l1_meas()->have_rssi)</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ms->l1_meas.have_rssi)</span><br><span>                vty_out(vty, "  RSSI:                   %d dBm%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                    ms->l1_meas()->rssi, VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (ms->l1_meas()->have_ber)</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms->l1_meas.rssi, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ms->l1_meas.have_ber)</span><br><span>                 vty_out(vty, "  Bit error rate:         %d %%%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ms->l1_meas()->ber, VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">- if (ms->l1_meas()->have_link_qual)</span><br><span style="color: hsl(120, 100%, 40%);">+                      ms->l1_meas.ber, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ms->l1_meas.have_link_qual)</span><br><span>           vty_out(vty, "  Link quality:           %d dB%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ms->l1_meas()->link_qual, VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (ms->l1_meas()->have_bto)</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms->l1_meas.link_qual, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ms->l1_meas.have_bto)</span><br><span>                 vty_out(vty, "  Burst timing offset:    %d/4 bit%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                  ms->l1_meas()->bto, VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">- if (ms->l1_meas()->have_ms_rx_qual)</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms->l1_meas.bto, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ms->l1_meas.have_ms_rx_qual)</span><br><span>          vty_out(vty, "  Downlink NACK rate:     %d %%%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ms->nack_rate_dl(), VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (ms->l1_meas()->have_ms_rx_qual)</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms_nack_rate_dl(ms), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ms->l1_meas.have_ms_rx_qual)</span><br><span>          vty_out(vty, "  MS RX quality:          %d %%%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ms->l1_meas()->ms_rx_qual, VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (ms->l1_meas()->have_ms_c_value)</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms->l1_meas.ms_rx_qual, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ms->l1_meas.have_ms_c_value)</span><br><span>          vty_out(vty, "  MS C value:             %d dB%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ms->l1_meas()->ms_c_value, VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (ms->l1_meas()->have_ms_sign_var)</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms->l1_meas.ms_c_value, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ms->l1_meas.have_ms_sign_var)</span><br><span>                 vty_out(vty, "  MS SIGN variance:       %d dB%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ms->l1_meas()->ms_sign_var, VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">- for (i = 0; i < ARRAY_SIZE(ms->l1_meas()->ts); ++i) {</span><br><span style="color: hsl(0, 100%, 40%);">-          if (ms->l1_meas()->ts[i].have_ms_i_level)</span><br><span style="color: hsl(120, 100%, 40%);">+                       ms->l1_meas.ms_sign_var, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < ARRAY_SIZE(ms->l1_meas.ts); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ms->l1_meas.ts[i].have_ms_i_level)</span><br><span>                    vty_out(vty, "  MS I level (slot %d):    %d dB%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                            i, ms->l1_meas()->ts[i].ms_i_level, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                               i, ms->l1_meas.ts[i].ms_i_level, VTY_NEWLINE);</span><br><span>    }</span><br><span style="color: hsl(0, 100%, 40%);">-       vty_out(vty, "  RLC/MAC DL Control Msg: %d%s", ms->dl_ctrl_msg(),</span><br><span style="color: hsl(120, 100%, 40%);">+        vty_out(vty, "  RLC/MAC DL Control Msg: %d%s", ms_dl_ctrl_msg(ms),</span><br><span>                 VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (ms->ul_tbf())</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ms_ul_tbf(ms))</span><br><span>           vty_out(vty, "  Uplink TBF:             TFI=%d, state=%s%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                  ms->ul_tbf()->tfi(),</span><br><span style="color: hsl(0, 100%, 40%);">-                      ms->ul_tbf()->state_name(),</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms_ul_tbf(ms)->tfi(),</span><br><span style="color: hsl(120, 100%, 40%);">+                      ms_ul_tbf(ms)->state_name(),</span><br><span>                      VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (ms->dl_tbf()) {</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ms_dl_tbf(ms)) {</span><br><span>                 vty_out(vty, "  Downlink TBF:           TFI=%d, state=%s%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                  ms->dl_tbf()->tfi(),</span><br><span style="color: hsl(0, 100%, 40%);">-                      ms->dl_tbf()->state_name(),</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms_dl_tbf(ms)->tfi(),</span><br><span style="color: hsl(120, 100%, 40%);">+                      ms_dl_tbf(ms)->state_name(),</span><br><span>                      VTY_NEWLINE);</span><br><span>                vty_out(vty, "  Current DL Throughput:  %d Kbps %s",</span><br><span style="color: hsl(0, 100%, 40%);">-                  ms->dl_tbf()->m_bw.dl_throughput,</span><br><span style="color: hsl(120, 100%, 40%);">+                       ms_dl_tbf(ms)->m_bw.dl_throughput,</span><br><span>                        VTY_NEWLINE);</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   llist_for_each(i_tbf, &ms->old_tbfs())</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(i_tbf, &ms->old_tbfs, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)i_tbf->entry;</span><br><span>             vty_out(vty, "  Old %-19s TFI=%d, state=%s%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                        i_tbf->entry()->direction == GPRS_RLCMAC_UL_TBF ?</span><br><span style="color: hsl(120, 100%, 40%);">+                       tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF ?</span><br><span>                   "Uplink TBF:" : "Downlink TBF:",</span><br><span style="color: hsl(0, 100%, 40%);">-                    i_tbf->entry()->tfi(),</span><br><span style="color: hsl(0, 100%, 40%);">-                    i_tbf->entry()->state_name(),</span><br><span style="color: hsl(120, 100%, 40%);">+                   tbf->tfi(),</span><br><span style="color: hsl(120, 100%, 40%);">+                        tbf->state_name(),</span><br><span>                        VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span>        return CMD_SUCCESS;</span><br><span> }</span><br><span>@@ -206,10 +208,10 @@</span><br><span> int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)</span><br><span> {</span><br><span>  BTS *bts = bts_data->bts;</span><br><span style="color: hsl(0, 100%, 40%);">-    LListHead<GprsMs> *ms_iter;</span><br><span style="color: hsl(120, 100%, 40%);">+     GprsMs *ms_iter;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    llist_for_each(ms_iter, &bts->ms_store().ms_list())</span><br><span style="color: hsl(0, 100%, 40%);">-              show_ms(vty, ms_iter->entry());</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(ms_iter, bts->ms_store().ms_list(), list)</span><br><span style="color: hsl(120, 100%, 40%);">+             show_ms(vty, ms_iter);</span><br><span> </span><br><span>   return CMD_SUCCESS;</span><br><span> }</span><br><span>diff --git a/src/pdch.cpp b/src/pdch.cpp</span><br><span>index 4a0ff06..49cce8d 100644</span><br><span>--- a/src/pdch.cpp</span><br><span>+++ b/src/pdch.cpp</span><br><span>@@ -68,9 +68,9 @@</span><br><span>            18, /* 18,10 % */</span><br><span>    };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  meas->set_ms_rx_qual(rx_qual_map[</span><br><span style="color: hsl(0, 100%, 40%);">-            OSMO_MIN(rx_qual_enc, ARRAY_SIZE(rx_qual_map)-1)</span><br><span style="color: hsl(0, 100%, 40%);">-                ]);</span><br><span style="color: hsl(120, 100%, 40%);">+   pcu_l1_meas_set_ms_rx_qual(meas, rx_qual_map[</span><br><span style="color: hsl(120, 100%, 40%);">+                                 OSMO_MIN(rx_qual_enc, ARRAY_SIZE(rx_qual_map)-1)</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ]);</span><br><span> }</span><br><span> </span><br><span> static void get_meas(struct pcu_l1_meas *meas,</span><br><span>@@ -78,9 +78,9 @@</span><br><span> {</span><br><span>      unsigned i;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- meas->set_ms_c_value(qr->C_VALUE);</span><br><span style="color: hsl(120, 100%, 40%);">+      pcu_l1_meas_set_ms_c_value(meas, qr->C_VALUE);</span><br><span>    if (qr->Exist_SIGN_VAR)</span><br><span style="color: hsl(0, 100%, 40%);">-              meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+         pcu_l1_meas_set_ms_sign_var(meas, (qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */</span><br><span> </span><br><span>   for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->I_LEVEL_TN), ARRAY_SIZE(meas->ts)); i++)</span><br><span>    {</span><br><span>@@ -88,7 +88,7 @@</span><br><span>                        LOGP(DRLCMAC, LOGL_INFO,</span><br><span>                             "Packet resource request: i_level[%d] = %d\n",</span><br><span>                             i, qr->I_LEVEL_TN[i].I_LEVEL);</span><br><span style="color: hsl(0, 100%, 40%);">-                       meas->set_ms_i_level(i, -2 * qr->I_LEVEL_TN[i].I_LEVEL);</span><br><span style="color: hsl(120, 100%, 40%);">+                        pcu_l1_meas_set_ms_i_level(meas, i, -2 * qr->I_LEVEL_TN[i].I_LEVEL);</span><br><span>              }</span><br><span>    }</span><br><span> }</span><br><span>@@ -99,8 +99,8 @@</span><br><span>   unsigned i;</span><br><span> </span><br><span>      get_rx_qual_meas(meas, qr->RXQUAL);</span><br><span style="color: hsl(0, 100%, 40%);">-  meas->set_ms_c_value(qr->C_VALUE);</span><br><span style="color: hsl(0, 100%, 40%);">-        meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+ pcu_l1_meas_set_ms_c_value(meas, qr->C_VALUE);</span><br><span style="color: hsl(120, 100%, 40%);">+     pcu_l1_meas_set_ms_sign_var(meas, (qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */</span><br><span> </span><br><span>   for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++)</span><br><span>  {</span><br><span>@@ -108,7 +108,7 @@</span><br><span>                      LOGP(DRLCMAC, LOGL_DEBUG,</span><br><span>                            "Channel quality report: i_level[%d] = %d\n",</span><br><span>                              i, qr->Slot[i].I_LEVEL_TN);</span><br><span style="color: hsl(0, 100%, 40%);">-                  meas->set_ms_i_level(i, -2 * qr->Slot[i].I_LEVEL_TN);</span><br><span style="color: hsl(120, 100%, 40%);">+                   pcu_l1_meas_set_ms_i_level(meas, i, -2 * qr->Slot[i].I_LEVEL_TN);</span><br><span>                 }</span><br><span>    }</span><br><span> }</span><br><span>@@ -307,11 +307,11 @@</span><br><span>                       LOGP(DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with "</span><br><span>                           "unknown TBF corresponds to MS with IMSI %s, TA %d, "</span><br><span>                              "uTBF (TFI=%d, state=%s), dTBF (TFI=%d, state=%s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                         ms->imsi(), ms->ta(),</span><br><span style="color: hsl(0, 100%, 40%);">-                             ms->ul_tbf() ? ms->ul_tbf()->tfi() : 0,</span><br><span style="color: hsl(0, 100%, 40%);">-                        ms->ul_tbf() ? ms->ul_tbf()->state_name() : "None",</span><br><span style="color: hsl(0, 100%, 40%);">-                          ms->dl_tbf() ? ms->dl_tbf()->tfi() : 0,</span><br><span style="color: hsl(0, 100%, 40%);">-                        ms->dl_tbf() ? ms->dl_tbf()->state_name() : "None");</span><br><span style="color: hsl(120, 100%, 40%);">+                       ms_imsi(ms), ms_ta(ms),</span><br><span style="color: hsl(120, 100%, 40%);">+                       ms_ul_tbf(ms) ? ms_ul_tbf(ms)->tfi() : 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                          ms_ul_tbf(ms) ? ms_ul_tbf(ms)->state_name() : "None",</span><br><span style="color: hsl(120, 100%, 40%);">+                            ms_dl_tbf(ms) ? ms_dl_tbf(ms)->tfi() : 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                          ms_dl_tbf(ms) ? ms_dl_tbf(ms)->state_name() : "None");</span><br><span>             return;</span><br><span>      }</span><br><span> </span><br><span>@@ -339,7 +339,7 @@</span><br><span>          tbf->n_reset(N3105);</span><br><span>              TBF_SET_ASS_STATE_DL(tbf, GPRS_RLCMAC_DL_ASS_NONE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-         new_tbf = tbf->ms() ? tbf->ms()->dl_tbf() : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+            new_tbf = tbf->ms() ? ms_dl_tbf(tbf->ms()) : NULL;</span><br><span>             if (!new_tbf) {</span><br><span>                      LOGP(DRLCMAC, LOGL_ERROR, "Got ACK, but DL "</span><br><span>                               "TBF is gone TLLI=0x%08x\n", tlli);</span><br><span>@@ -371,7 +371,7 @@</span><br><span>          tbf->n_reset(N3105);</span><br><span>              TBF_SET_ASS_STATE_UL(tbf, GPRS_RLCMAC_UL_ASS_NONE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-         new_tbf = tbf->ms() ? tbf->ms()->ul_tbf() : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+            new_tbf = tbf->ms() ? ms_ul_tbf(tbf->ms()) : NULL;</span><br><span>             if (!new_tbf) {</span><br><span>                      LOGP(DRLCMAC, LOGL_ERROR, "Got ACK, but UL "</span><br><span>                               "TBF is gone TLLI=0x%08x\n", tlli);</span><br><span>@@ -389,7 +389,7 @@</span><br><span>          /* there might be LLC packets waiting in the queue, but the DL</span><br><span>                * TBF might have been released while the UL TBF has been</span><br><span>             * established */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (new_tbf->ms()->need_dl_tbf())</span><br><span style="color: hsl(120, 100%, 40%);">+               if (ms_need_dl_tbf(new_tbf->ms()))</span><br><span>                        new_tbf->establish_dl_tbf_on_pacch();</span><br><span> </span><br><span>                 return;</span><br><span>@@ -460,7 +460,7 @@</span><br><span>        /* get measurements */</span><br><span>       if (tbf->ms()) {</span><br><span>          get_meas(meas, &ack_nack->Channel_Quality_Report);</span><br><span style="color: hsl(0, 100%, 40%);">-               tbf->ms()->update_l1_meas(meas);</span><br><span style="color: hsl(120, 100%, 40%);">+                ms_update_l1_meas(tbf->ms(), meas);</span><br><span>       }</span><br><span> }</span><br><span> </span><br><span>@@ -570,19 +570,19 @@</span><br><span>           if (!ms) {</span><br><span>                   ms_found = false;</span><br><span>                    ms = bts()->ms_alloc(0, 0); /* ms class updated later */</span><br><span style="color: hsl(0, 100%, 40%);">-                     ms->set_tlli(tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ms_set_tlli(ms, tlli);</span><br><span>               }</span><br><span style="color: hsl(0, 100%, 40%);">-               ul_tbf = ms->ul_tbf(); /* hence ul_tbf may be NULL */</span><br><span style="color: hsl(120, 100%, 40%);">+              ul_tbf = ms_ul_tbf(ms); /* hence ul_tbf may be NULL */</span><br><span> </span><br><span>           /* Keep the ms, even if it gets idle temporarily */</span><br><span style="color: hsl(0, 100%, 40%);">-             GprsMs::Guard guard(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_ref(ms);</span><br><span> </span><br><span>              LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "</span><br><span>                    "in packet resource request of single "</span><br><span>                    "block, so we provide one:\n");</span><br><span>            sba = bts()->sba()->find(this, fn);</span><br><span>            if (sba) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      ms->set_ta(sba->ta);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms_set_ta(ms, sba->ta);</span><br><span>                   bts()->sba()->free_sba(sba);</span><br><span>           } else if (!ul_tbf || !ul_tbf->state_is(GPRS_RLCMAC_FINISHED)) {</span><br><span>                  LOGPTBFUL(ul_tbf, LOGL_NOTICE,</span><br><span>@@ -599,9 +599,9 @@</span><br><span>                         ms_class = Decoding::get_ms_class_by_capability(&request->MS_Radio_Access_capability2);</span><br><span>                       egprs_ms_class = Decoding::get_egprs_ms_class_by_capability(&request->MS_Radio_Access_capability2);</span><br><span>                   if (ms_class)</span><br><span style="color: hsl(0, 100%, 40%);">-                           ms->set_ms_class(ms_class);</span><br><span style="color: hsl(120, 100%, 40%);">+                                ms_set_ms_class(ms, ms_class);</span><br><span>                       if (egprs_ms_class)</span><br><span style="color: hsl(0, 100%, 40%);">-                             ms->set_egprs_ms_class(egprs_ms_class);</span><br><span style="color: hsl(120, 100%, 40%);">+                            ms_set_egprs_ms_class(ms, egprs_ms_class);</span><br><span>           }</span><br><span> </span><br><span>                /* Get rid of previous finished UL TBF before providing a new one */</span><br><span>@@ -616,7 +616,7 @@</span><br><span>           if (!ul_tbf) {</span><br><span>                       handle_tbf_reject(bts_data(), ms, tlli,</span><br><span>                              trx_no(), ts_no);</span><br><span style="color: hsl(0, 100%, 40%);">-                       return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       goto return_unref;</span><br><span>           }</span><br><span> </span><br><span>                /* set control ts to current MS's TS, until assignment complete */</span><br><span>@@ -630,8 +630,10 @@</span><br><span>                /* get measurements */</span><br><span>               if (ul_tbf->ms()) {</span><br><span>                       get_meas(meas, request);</span><br><span style="color: hsl(0, 100%, 40%);">-                        ul_tbf->ms()->update_l1_meas(meas);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ms_update_l1_meas(ul_tbf->ms(), meas);</span><br><span>            }</span><br><span style="color: hsl(120, 100%, 40%);">+return_unref:</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_unref(ms);</span><br><span>                return;</span><br><span>      }</span><br><span> </span><br><span>@@ -674,10 +676,10 @@</span><br><span>                LOGP(DRLCMAC, LOGL_NOTICE, "MS send measurement "</span><br><span>               "but TLLI 0x%08x is unknown\n", report->TLLI);</span><br><span>             ms = bts()->ms_alloc(0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-          ms->set_tlli(report->TLLI);</span><br><span style="color: hsl(120, 100%, 40%);">+             ms_set_tlli(ms, report->TLLI);</span><br><span>    }</span><br><span>    if ((sba = bts()->sba()->find(this, fn))) {</span><br><span style="color: hsl(0, 100%, 40%);">-               ms->set_ta(sba->ta);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms_set_ta(ms, sba->ta);</span><br><span>           bts()->sba()->free_sba(sba);</span><br><span>   }</span><br><span>    gprs_rlcmac_meas_rep(ms, report);</span><br><span>diff --git a/src/tbf.cpp b/src/tbf.cpp</span><br><span>index e92dfb6..fde44ba 100644</span><br><span>--- a/src/tbf.cpp</span><br><span>+++ b/src/tbf.cpp</span><br><span>@@ -141,14 +141,13 @@</span><br><span>   m_tfi(0),</span><br><span>    m_created_ts(0),</span><br><span>     m_ctrs(NULL),</span><br><span style="color: hsl(0, 100%, 40%);">-   m_ms(ms),</span><br><span>    state(GPRS_RLCMAC_NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+      m_ms(ms),</span><br><span>    dl_ass_state(GPRS_RLCMAC_DL_ASS_NONE),</span><br><span>       ul_ass_state(GPRS_RLCMAC_UL_ASS_NONE),</span><br><span>       ul_ack_state(GPRS_RLCMAC_UL_ACK_NONE),</span><br><span>       poll_state(GPRS_RLCMAC_POLL_NONE),</span><br><span>   m_list(this),</span><br><span style="color: hsl(0, 100%, 40%);">-   m_ms_list(this),</span><br><span>     m_egprs_enabled(false)</span><br><span> {</span><br><span>  /* The classes of these members do not have proper constructors yet.</span><br><span>@@ -158,6 +157,9 @@</span><br><span>   memset(&Narr, 0, sizeof(Narr));</span><br><span>  memset(&gsm_timer, 0, sizeof(gsm_timer));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     memset(&m_ms_list, 0, sizeof(m_ms_list));</span><br><span style="color: hsl(120, 100%, 40%);">+ m_ms_list.entry = this;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    m_rlc.init();</span><br><span>        m_llc.init();</span><br><span> </span><br><span>@@ -171,27 +173,27 @@</span><br><span> </span><br><span> uint32_t gprs_rlcmac_tbf::tlli() const</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    return m_ms ? m_ms->tlli() : GSM_RESERVED_TMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+    return m_ms ? ms_tlli(m_ms) : GSM_RESERVED_TMSI;</span><br><span> }</span><br><span> </span><br><span> const char *gprs_rlcmac_tbf::imsi() const</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     return m_ms->imsi();</span><br><span style="color: hsl(120, 100%, 40%);">+       return ms_imsi(m_ms);</span><br><span> }</span><br><span> </span><br><span> uint8_t gprs_rlcmac_tbf::ta() const</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      return m_ms->ta();</span><br><span style="color: hsl(120, 100%, 40%);">+ return ms_ta(m_ms);</span><br><span> }</span><br><span> </span><br><span> void gprs_rlcmac_tbf::set_ta(uint8_t ta)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   ms()->set_ta(ta);</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_set_ta(m_ms, ta);</span><br><span> }</span><br><span> </span><br><span> uint8_t gprs_rlcmac_tbf::ms_class() const</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return m_ms->ms_class();</span><br><span style="color: hsl(120, 100%, 40%);">+   return ms_ms_class(m_ms);</span><br><span> }</span><br><span> </span><br><span> enum CodingScheme gprs_rlcmac_tbf::current_cs() const</span><br><span>@@ -199,28 +201,21 @@</span><br><span>  enum CodingScheme cs;</span><br><span> </span><br><span>    if (direction == GPRS_RLCMAC_UL_TBF)</span><br><span style="color: hsl(0, 100%, 40%);">-            cs = m_ms ? m_ms->current_cs_ul() : UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+               cs = m_ms ? ms_current_cs_ul(m_ms) : UNKNOWN;</span><br><span>        else</span><br><span style="color: hsl(0, 100%, 40%);">-            cs = m_ms ? m_ms->current_cs_dl() : UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+               cs = m_ms ? ms_current_cs_dl(m_ms) : UNKNOWN;</span><br><span> </span><br><span>    return cs;</span><br><span> }</span><br><span> </span><br><span> gprs_llc_queue *gprs_rlcmac_tbf::llc_queue()</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        return m_ms ? m_ms->llc_queue() : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    return m_ms ? ms_llc_queue(m_ms) : NULL;</span><br><span> }</span><br><span> </span><br><span> const gprs_llc_queue *gprs_rlcmac_tbf::llc_queue() const</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      return m_ms ? m_ms->llc_queue() : NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-size_t gprs_rlcmac_tbf::llc_queue_size() const</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      /* m_ms->llc_queue() never returns NULL: GprsMs::m_llc_queue is a</span><br><span style="color: hsl(0, 100%, 40%);">-     * member instance. */</span><br><span style="color: hsl(0, 100%, 40%);">-  return m_ms ? m_ms->llc_queue()->size() : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    return ms_llc_queue(m_ms);</span><br><span> }</span><br><span> </span><br><span> void gprs_rlcmac_tbf::set_ms(GprsMs *ms)</span><br><span>@@ -229,13 +224,13 @@</span><br><span>              return;</span><br><span> </span><br><span>  if (m_ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-             m_ms->detach_tbf(this);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms_detach_tbf(m_ms, this);</span><br><span>   }</span><br><span> </span><br><span>        m_ms = ms;</span><br><span> </span><br><span>       if (m_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-               m_ms->attach_tbf(this);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms_attach_tbf(m_ms, this);</span><br><span> }</span><br><span> </span><br><span> void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)</span><br><span>@@ -247,18 +242,18 @@</span><br><span>     * MS object that belongs to that TLLI and if yes make sure one of them</span><br><span>       * gets deleted. This is the same problem that can arise with</span><br><span>         * IMSI in gprs_rlcmac_dl_tbf::handle() so there should be a unified solution */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!ms()->check_tlli(tlli)) {</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ms_check_tlli(ms(), tlli)) {</span><br><span>            GprsMs *old_ms;</span><br><span> </span><br><span>          old_ms = bts->ms_store().get_ms(tlli, 0, NULL);</span><br><span>           if (old_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-                     ms()->merge_and_clear_ms(old_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+                  ms_merge_and_clear_ms(ms(), old_ms);</span><br><span>         }</span><br><span> </span><br><span>        if (dir == GPRS_RLCMAC_UL_TBF)</span><br><span style="color: hsl(0, 100%, 40%);">-          ms()->set_tlli(tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_set_tlli(ms(), tlli);</span><br><span>     else</span><br><span style="color: hsl(0, 100%, 40%);">-            ms()->confirm_tlli(tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_confirm_tlli(ms(), tlli);</span><br><span> }</span><br><span> </span><br><span> static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)</span><br><span>@@ -745,7 +740,7 @@</span><br><span>      struct gprs_rlcmac_bts *bts_data = bts->bts_data();</span><br><span>       int rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if (m_ms->mode() != GPRS)</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ms_mode(m_ms) != GPRS)</span><br><span>           enable_egprs();</span><br><span> </span><br><span>  m_created_ts = time(NULL);</span><br><span>@@ -775,7 +770,7 @@</span><br><span>             return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   m_ms->attach_tbf(this);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(m_ms, this);</span><br><span> </span><br><span>       return 0;</span><br><span> }</span><br><span>@@ -895,7 +890,7 @@</span><br><span>         }</span><br><span> </span><br><span>        if (ms())</span><br><span style="color: hsl(0, 100%, 40%);">-               new_dl_tbf = ms()->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+               new_dl_tbf = ms_dl_tbf(ms());</span><br><span> </span><br><span>    if (!new_dl_tbf) {</span><br><span>           LOGPTBFDL(this, LOGL_ERROR,</span><br><span>@@ -1012,7 +1007,7 @@</span><br><span>          return NULL;</span><br><span> </span><br><span>     if (ms())</span><br><span style="color: hsl(0, 100%, 40%);">-               new_tbf = ms()->ul_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+          new_tbf = ms_ul_tbf(ms());</span><br><span>   if (!new_tbf) {</span><br><span>              LOGPTBFUL(this, LOGL_ERROR,</span><br><span>                    "We have a schedule for uplink assignment, but there is no uplink TBF\n");</span><br><span>@@ -1170,3 +1165,58 @@</span><br><span> {</span><br><span>         return ts == control_ts;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* C API */</span><br><span style="color: hsl(120, 100%, 40%);">+enum gprs_rlcmac_tbf_state tbf_state(const struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return tbf->state;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum gprs_rlcmac_tbf_direction tbf_direction(const struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return tbf->direction;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void tbf_set_ms(struct gprs_rlcmac_tbf *tbf, GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   tbf->set_ms(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct llist_head *tbf_ms_list(struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return &tbf->m_ms_list.list;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs *tbf_ms(struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return tbf->ms();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool tbf_timers_pending(struct gprs_rlcmac_tbf *tbf, enum tbf_timers t)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return tbf->timers_pending(t);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_llc *tbf_llc(struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return &tbf->m_llc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t tbf_first_common_ts(const struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return tbf->first_common_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t tbf_dl_slots(const struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return tbf->dl_slots();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t tbf_ul_slots(const struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return tbf->ul_slots();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool tbf_is_tfi_assigned(const struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return tbf->is_tfi_assigned();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/tbf.h b/src/tbf.h</span><br><span>index c97477b..4bbfea2 100644</span><br><span>--- a/src/tbf.h</span><br><span>+++ b/src/tbf.h</span><br><span>@@ -25,11 +25,21 @@</span><br><span> #include "llc.h"</span><br><span> #include "rlc.h"</span><br><span> #include "cxx_linuxlist.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "pcu_utils.h"</span><br><span> #include <gprs_debug.h></span><br><span> #include <gsm_timer.h></span><br><span> #include <stdint.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct bssgp_bvc_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_bts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/core/linuxlist.h></span><br><span> #include <osmocom/core/logging.h></span><br><span>@@ -37,12 +47,8 @@</span><br><span> #include <osmocom/gsm/gsm48.h></span><br><span> </span><br><span> #include "coding_scheme.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct bssgp_bvc_ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-class GprsMs;</span><br><span style="color: hsl(0, 100%, 40%);">-struct gprs_rlcmac_bts;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> #endif</span><br><span> </span><br><span> /*</span><br><span>@@ -182,6 +188,28 @@</span><br><span> #define TBF_ASS_TYPE_UNSET(t, kind) do { t->ass_type_mod(kind, true, __FILE__, __LINE__); } while(0)</span><br><span> </span><br><span> #ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+const char *tbf_name(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+enum gprs_rlcmac_tbf_state tbf_state(const struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+enum gprs_rlcmac_tbf_direction tbf_direction(const struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+void tbf_set_ms(struct gprs_rlcmac_tbf *tbf, struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+struct llist_head *tbf_ms_list(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs *tbf_ms(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+bool tbf_timers_pending(struct gprs_rlcmac_tbf *tbf, enum tbf_timers t);</span><br><span style="color: hsl(120, 100%, 40%);">+void tbf_free(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_llc *tbf_llc(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t tbf_first_common_ts(const struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t tbf_dl_slots(const struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t tbf_ul_slots(const struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+bool tbf_is_tfi_assigned(const struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> </span><br><span> struct gprs_rlcmac_tbf {</span><br><span>    gprs_rlcmac_tbf(BTS *bts_, GprsMs *ms, gprs_rlcmac_tbf_direction dir);</span><br><span>@@ -255,7 +283,6 @@</span><br><span>         void set_ta(uint8_t);</span><br><span>        uint8_t ms_class() const;</span><br><span>    enum CodingScheme current_cs() const;</span><br><span style="color: hsl(0, 100%, 40%);">-   size_t llc_queue_size() const;</span><br><span> </span><br><span>   time_t created_ts() const;</span><br><span>   uint8_t dl_slots() const;</span><br><span>@@ -269,9 +296,6 @@</span><br><span>      /* attempt to make things a bit more fair */</span><br><span>         void rotate_in_list();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      LListHead<gprs_rlcmac_tbf>& ms_list() {return this->m_ms_list;}</span><br><span style="color: hsl(0, 100%, 40%);">-    const LListHead<gprs_rlcmac_tbf>& ms_list() const {return this->m_ms_list;}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>     LListHead<gprs_rlcmac_tbf>& list();</span><br><span>        const LListHead<gprs_rlcmac_tbf>& list() const;</span><br><span> </span><br><span>@@ -321,6 +345,8 @@</span><br><span>  time_t m_created_ts;</span><br><span> </span><br><span>     struct rate_ctr_group *m_ctrs;</span><br><span style="color: hsl(120, 100%, 40%);">+        enum gprs_rlcmac_tbf_state state;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_item m_ms_list;</span><br><span> </span><br><span> protected:</span><br><span>       gprs_rlcmac_bts *bts_data() const;</span><br><span>@@ -331,26 +357,20 @@</span><br><span> </span><br><span>       static const char *tbf_state_name[6];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       class GprsMs *m_ms;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct GprsMs *m_ms;</span><br><span> private:</span><br><span>     void enable_egprs();</span><br><span style="color: hsl(0, 100%, 40%);">-    enum gprs_rlcmac_tbf_state state;</span><br><span>    enum gprs_rlcmac_tbf_dl_ass_state dl_ass_state;</span><br><span>      enum gprs_rlcmac_tbf_ul_ass_state ul_ass_state;</span><br><span>      enum gprs_rlcmac_tbf_ul_ack_state ul_ack_state;</span><br><span>      enum gprs_rlcmac_tbf_poll_state poll_state;</span><br><span>  LListHead<gprs_rlcmac_tbf> m_list;</span><br><span style="color: hsl(0, 100%, 40%);">-        LListHead<gprs_rlcmac_tbf> m_ms_list;</span><br><span>  bool m_egprs_enabled;</span><br><span>        struct osmo_timer_list Tarr[T_MAX];</span><br><span>  uint8_t Narr[N_MAX];</span><br><span>         mutable char m_name_buf[60];</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void tbf_free(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> inline bool gprs_rlcmac_tbf::state_is(enum gprs_rlcmac_tbf_state rhs) const</span><br><span> {</span><br><span>         return state == rhs;</span><br><span>@@ -381,8 +401,6 @@</span><br><span>   return state != rhs;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-const char *tbf_name(gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> inline const char *gprs_rlcmac_tbf::state_name() const</span><br><span> {</span><br><span>      return tbf_state_name[state];</span><br><span>diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp</span><br><span>index bb89e81..613f7b8 100644</span><br><span>--- a/src/tbf_dl.cpp</span><br><span>+++ b/src/tbf_dl.cpp</span><br><span>@@ -131,7 +131,7 @@</span><br><span> </span><br><span>         LOGP(DTBF, LOGL_DEBUG, "********** DL-TBF starts here **********\n");</span><br><span>      LOGP(DTBF, LOGL_INFO, "Allocating DL TBF: MS_CLASS=%d/%d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-       ms->ms_class(), ms->egprs_ms_class());</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_ms_class(ms), ms_egprs_ms_class(ms));</span><br><span> </span><br><span>    tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);</span><br><span> </span><br><span>@@ -241,7 +241,7 @@</span><br><span>     struct gprs_rlcmac_ul_tbf *ul_tbf = NULL, *old_ul_tbf;</span><br><span>       struct gprs_rlcmac_dl_tbf *dl_tbf = NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ul_tbf = ms->ul_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+     ul_tbf = ms_ul_tbf(ms);</span><br><span> </span><br><span>  if (ul_tbf && ul_tbf->m_contention_resolution_done</span><br><span>         && !ul_tbf->m_final_ack_sent) {</span><br><span>@@ -291,41 +291,43 @@</span><br><span>  /* check for existing TBF */</span><br><span>         ms = bts->bts->ms_store().get_ms(tlli, tlli_old, imsi);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       if (ms && strlen(ms->imsi()) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ms && strlen(ms_imsi(ms)) == 0) {</span><br><span>                ms_old = bts->bts->ms_store().get_ms(0, 0, imsi);</span><br><span>              if (ms_old && ms_old != ms) {</span><br><span>                        /* The TLLI has changed (RAU), so there are two MS</span><br><span>                    * objects for the same MS */</span><br><span>                        LOGP(DTBF, LOGL_NOTICE,</span><br><span>                           "There is a new MS object for the same MS: (0x%08x, '%s') -> (0x%08x, '%s')\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                            ms_old->tlli(), ms_old->imsi(), ms->tlli(), ms->imsi());</span><br><span style="color: hsl(120, 100%, 40%);">+                          ms_tlli(ms_old), ms_imsi(ms_old), ms_tlli(ms), ms_imsi(ms));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                   GprsMs::Guard guard_old(ms_old);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ms_ref(ms_old);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                     if (!ms->dl_tbf() && ms_old->dl_tbf()) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (!ms_dl_tbf(ms) && ms_dl_tbf(ms_old)) {</span><br><span>                           LOGP(DTBF, LOGL_NOTICE,</span><br><span>                                   "IMSI %s, old TBF %s: moving DL TBF to new MS object\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                              imsi, ms_old->dl_tbf()->name());</span><br><span style="color: hsl(0, 100%, 40%);">-                             dl_tbf = ms_old->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+                              imsi, ms_dl_tbf(ms_old)->name());</span><br><span style="color: hsl(120, 100%, 40%);">+                             dl_tbf = ms_dl_tbf(ms_old);</span><br><span>                          /* Move the DL TBF to the new MS */</span><br><span>                          dl_tbf->set_ms(ms);</span><br><span>                       }</span><br><span style="color: hsl(0, 100%, 40%);">-                       ms->merge_and_clear_ms(ms_old);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms_merge_and_clear_ms(ms, ms_old);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  ms_unref(ms_old);</span><br><span>            }</span><br><span>    }</span><br><span> </span><br><span>        if (!ms)</span><br><span>             ms = bts->bts->ms_alloc(ms_class, egprs_ms_class);</span><br><span style="color: hsl(0, 100%, 40%);">-        ms->set_imsi(imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-  ms->confirm_tlli(tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!ms->ms_class() && ms_class) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ms->set_ms_class(ms_class);</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_set_imsi(ms, imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_confirm_tlli(ms, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ms_ms_class(ms) && ms_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ms_set_ms_class(ms, ms_class);</span><br><span>       }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!ms->egprs_ms_class() && egprs_ms_class) {</span><br><span style="color: hsl(0, 100%, 40%);">-               ms->set_egprs_ms_class(egprs_ms_class);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ms_egprs_ms_class(ms) && egprs_ms_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ms_set_egprs_ms_class(ms, egprs_ms_class);</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   dl_tbf = ms->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+     dl_tbf = ms_dl_tbf(ms);</span><br><span>      if (!dl_tbf) {</span><br><span>               rc = tbf_new_dl_assignment(bts, ms, &dl_tbf);</span><br><span>            if (rc < 0)</span><br><span>@@ -344,7 +346,7 @@</span><br><span>         uint32_t octets = 0, frames = 0;</span><br><span>     struct timespec hyst_delta = {0, 0};</span><br><span>         const unsigned keep_small_thresh = 60;</span><br><span style="color: hsl(0, 100%, 40%);">-  const gprs_llc_queue::MetaInfo *info;</span><br><span style="color: hsl(120, 100%, 40%);">+ const MetaInfo *info;</span><br><span> </span><br><span>    if (bts_data()->llc_discard_csec)</span><br><span>                 csecs_to_timespec(bts_data()->llc_discard_csec, &hyst_delta);</span><br><span>@@ -358,9 +360,9 @@</span><br><span> </span><br><span>               gprs_bssgp_update_queue_delay(tv_recv, &tv_now);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                if (ms() && ms()->codel_state()) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   int bytes = llc_queue()->octets();</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (gprs_codel_control(ms()->codel_state(),</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ms() && ms_codel_state(ms())) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   int bytes = llc_queue_octets(llc_queue());</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (gprs_codel_control(ms_codel_state(ms()),</span><br><span>                                         tv_recv, &tv_now, bytes))</span><br><span>                                goto drop_frame;</span><br><span>             }</span><br><span>@@ -402,7 +404,7 @@</span><br><span>              LOGPTBFDL(this, LOGL_NOTICE, "Discarding LLC PDU "</span><br><span>                         "because lifetime limit reached, "</span><br><span>                         "count=%u new_queue_size=%zu\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                        frames, llc_queue_size());</span><br><span style="color: hsl(120, 100%, 40%);">+                    frames, llc_queue_size(llc_queue()));</span><br><span>              if (frames > 0xff)</span><br><span>                        frames = 0xff;</span><br><span>               if (octets > 0xffffff)</span><br><span>@@ -459,7 +461,7 @@</span><br><span>      } else if (bsn < 0 && is_egprs_enabled() && req_mcs_kind == EGPRS_GMSK) {</span><br><span>                 /* New data to be sent for EGPRS TBF but we are required to downgrade to</span><br><span>              * MCS1-4, because USF for GPRS-only MS will be sent */</span><br><span style="color: hsl(0, 100%, 40%);">-         force_cs = m_ms->current_cs_dl();</span><br><span style="color: hsl(120, 100%, 40%);">+          force_cs = ms_current_cs_dl(m_ms);</span><br><span>           if (force_cs > MCS4) {</span><br><span>                    force_cs = bts->cs_dl_is_supported(MCS4) ? MCS4 :</span><br><span>                                    bts->cs_dl_is_supported(MCS3) ? MCS3 :</span><br><span>@@ -467,7 +469,7 @@</span><br><span>                              MCS1;</span><br><span>                     LOGPTBFDL(this, LOGL_DEBUG,</span><br><span>                            "Force downgrading DL %s -> %s due to USF for GPRS-only MS\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                             mcs_name(m_ms->current_cs_dl()), mcs_name(force_cs));</span><br><span style="color: hsl(120, 100%, 40%);">+                              mcs_name(ms_current_cs_dl(m_ms)), mcs_name(force_cs));</span><br><span>             }</span><br><span>    }</span><br><span> </span><br><span>@@ -483,14 +485,14 @@</span><br><span>                if (is_egprs_enabled()) {</span><br><span>                    /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */</span><br><span>                      m_rlc.block(bsn)->cs_current_trans = get_retx_mcs(m_rlc.block(bsn)->cs_init,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                        ms()->current_cs_dl(),</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                     ms_current_cs_dl(ms()),</span><br><span>                                                                      !bts->bts_data()->dl_arq_type);</span><br><span> </span><br><span>                  LOGPTBFDL(this, LOGL_DEBUG,</span><br><span>                            "initial_cs_dl(%s) last_mcs(%s) demanded_mcs(%s) cs_trans(%s) arq_type(%d) bsn(%d)\n",</span><br><span>                             mcs_name(m_rlc.block(bsn)->cs_init),</span><br><span>                              mcs_name(m_rlc.block(bsn)->cs_last),</span><br><span style="color: hsl(0, 100%, 40%);">-                                 mcs_name(ms()->current_cs_dl()),</span><br><span style="color: hsl(120, 100%, 40%);">+                           mcs_name(ms_current_cs_dl(ms())),</span><br><span>                            mcs_name(m_rlc.block(bsn)->cs_current_trans),</span><br><span>                             bts->bts_data()->dl_arq_type, bsn);</span><br><span> </span><br><span>@@ -635,7 +637,7 @@</span><br><span> {</span><br><span>   struct msgb *msg;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (m_llc.frame_length() != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+        if (llc_frame_length(&m_llc) != 0)</span><br><span>               return;</span><br><span> </span><br><span>  /* dequeue next LLC frame, if any */</span><br><span>@@ -661,7 +663,7 @@</span><br><span>   int write_offset = 0;</span><br><span>        Encoding::AppendResult ar;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  if (m_llc.frame_length() == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+        if (llc_frame_length(&m_llc) == 0)</span><br><span>               schedule_next_frame();</span><br><span> </span><br><span>   OSMO_ASSERT(mcs_is_valid(cs));</span><br><span>@@ -693,7 +695,7 @@</span><br><span>                 bool is_final;</span><br><span>               int payload_written = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            if (m_llc.frame_length() == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (llc_frame_length(&m_llc) == 0) {</span><br><span>                     /* It is not clear, when the next real data will</span><br><span>                      * arrive, so request a DL ack/nack now */</span><br><span>                   request_dl_ack();</span><br><span>@@ -731,10 +733,10 @@</span><br><span> </span><br><span>                        LOGPTBFDL(this, LOGL_DEBUG,</span><br><span>                            "Empty chunk, added LLC dummy command of size %d, drained_since=%d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                m_llc.frame_length(), frames_since_last_drain(fn));</span><br><span style="color: hsl(120, 100%, 40%);">+                           llc_frame_length(&m_llc), frames_since_last_drain(fn));</span><br><span>                }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           is_final = llc_queue_size() == 0 && !keep_open(fn);</span><br><span style="color: hsl(120, 100%, 40%);">+           is_final = llc_queue_size(llc_queue()) == 0 && !keep_open(fn);</span><br><span> </span><br><span>           ar = Encoding::rlc_data_to_dl_append(rdbi, cs,</span><br><span>                       &m_llc, &write_offset, &num_chunks, data, is_final, &payload_written);</span><br><span>@@ -745,9 +747,9 @@</span><br><span>                 if (ar == Encoding::AR_NEED_MORE_BLOCKS)</span><br><span>                     break;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              LOGPTBFDL(this, LOGL_DEBUG, "Complete DL frame, len=%d\n", m_llc.frame_length());</span><br><span style="color: hsl(0, 100%, 40%);">-             gprs_rlcmac_dl_bw(this, m_llc.frame_length());</span><br><span style="color: hsl(0, 100%, 40%);">-          bts->do_rate_ctr_add(CTR_LLC_DL_BYTES, m_llc.frame_length());</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPTBFDL(this, LOGL_DEBUG, "Complete DL frame, len=%d\n", llc_frame_length(&m_llc));</span><br><span style="color: hsl(120, 100%, 40%);">+           gprs_rlcmac_dl_bw(this, llc_frame_length(&m_llc));</span><br><span style="color: hsl(120, 100%, 40%);">+                bts->do_rate_ctr_add(CTR_LLC_DL_BYTES, llc_frame_length(&m_llc));</span><br><span>             m_llc.reset();</span><br><span> </span><br><span>           if (is_final) {</span><br><span>@@ -1131,7 +1133,7 @@</span><br><span>      error_rate = analyse_errors(show_rbb, behind_last_bsn, &ana_res);</span><br><span> </span><br><span>    if (bts_data()->cs_adj_enabled && ms())</span><br><span style="color: hsl(0, 100%, 40%);">-              ms()->update_error_rate(this, error_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+         ms_update_error_rate(ms(), this, error_rate);</span><br><span> </span><br><span>    m_window.update(bts, rbb, first_bsn, &lost, &received);</span><br><span>      rate_ctr_add(&m_ctrs->ctr[TBF_CTR_RLC_NACKED], lost);</span><br><span>@@ -1186,7 +1188,7 @@</span><br><span>         error_rate = analyse_errors(show_rbb, ssn, &ana_res);</span><br><span> </span><br><span>        if (bts_data()->cs_adj_enabled && ms())</span><br><span style="color: hsl(0, 100%, 40%);">-              ms()->update_error_rate(this, error_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+         ms_update_error_rate(ms(), this, error_rate);</span><br><span> </span><br><span>    m_window.update(bts, show_rbb, ssn,</span><br><span>                  &lost, &received);</span><br><span>@@ -1221,7 +1223,7 @@</span><br><span>   release();</span><br><span> </span><br><span>       /* check for LLC PDU in the LLC Queue */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (llc_queue_size() > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+  if (llc_queue_size(llc_queue()) > 0)</span><br><span>              /* we have more data so we will re-use this tbf */</span><br><span>           establish_dl_tbf_on_pacch();</span><br><span> </span><br><span>@@ -1331,8 +1333,8 @@</span><br><span> </span><br><span> bool gprs_rlcmac_dl_tbf::have_data() const</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return m_llc.chunk_size() > 0 ||</span><br><span style="color: hsl(0, 100%, 40%);">-             (llc_queue_size() > 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    return llc_chunk_size(&m_llc) > 0 ||</span><br><span style="color: hsl(120, 100%, 40%);">+           (llc_queue_size(llc_queue()) > 0);</span><br><span> }</span><br><span> </span><br><span> static inline int frames_since_last(int32_t last, unsigned fn)</span><br><span>@@ -1556,3 +1558,11 @@</span><br><span>                      mcs_name(cs));</span><br><span>     }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_dl_tbf *as_dl_tbf(struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (tbf && tbf->direction == GPRS_RLCMAC_DL_TBF)</span><br><span style="color: hsl(120, 100%, 40%);">+           return static_cast<gprs_rlcmac_dl_tbf *>(tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/tbf_dl.h b/src/tbf_dl.h</span><br><span>index ffb370c..3cd88c9 100644</span><br><span>--- a/src/tbf_dl.h</span><br><span>+++ b/src/tbf_dl.h</span><br><span>@@ -141,15 +141,17 @@</span><br><span>         return m_window.ws();</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline gprs_rlcmac_dl_tbf *as_dl_tbf(gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       if (tbf && tbf->direction == GPRS_RLCMAC_DL_TBF)</span><br><span style="color: hsl(0, 100%, 40%);">-             return static_cast<gprs_rlcmac_dl_tbf *>(tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-    else</span><br><span style="color: hsl(0, 100%, 40%);">-            return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts, GprsMs *ms,</span><br><span>                                            int8_t use_trx, bool single_slot);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#else /* ifdef __cplusplus */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_dl_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_dl_tbf *as_dl_tbf(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> #endif</span><br><span>diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp</span><br><span>index 80a8eaa..f8c860c 100644</span><br><span>--- a/src/tbf_ul.cpp</span><br><span>+++ b/src/tbf_ul.cpp</span><br><span>@@ -105,7 +105,7 @@</span><br><span> </span><br><span>      LOGP(DTBF, LOGL_DEBUG, "********** UL-TBF starts here **********\n");</span><br><span>      LOGP(DTBF, LOGL_INFO, "Allocating UL TBF: MS_CLASS=%d/%d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-       ms->ms_class(), ms->egprs_ms_class());</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_ms_class(ms), ms_egprs_ms_class(ms));</span><br><span> </span><br><span>    tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);</span><br><span>       if (!tbf)</span><br><span>@@ -172,7 +172,7 @@</span><br><span> </span><br><span>  if (!ms)</span><br><span>             ms = bts->bts->ms_alloc(0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_tlli(tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_set_tlli(ms, tlli);</span><br><span> </span><br><span>   ul_tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);</span><br><span>    if (!ul_tbf)</span><br><span>@@ -185,7 +185,7 @@</span><br><span>   ul_tbf->bts->do_rate_ctr_inc(CTR_TBF_UL_ALLOCATED);</span><br><span>    TBF_SET_ASS_ON(ul_tbf, GPRS_RLCMAC_FLAG_PACCH, false);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      ms->attach_tbf(ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(ms, ul_tbf);</span><br><span>   ul_tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);</span><br><span>      TBF_SET_ASS_STATE_UL(ul_tbf, GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ);</span><br><span>       ul_tbf->control_ts = ts;</span><br><span>@@ -252,14 +252,14 @@</span><br><span>                          frame->is_complete);</span><br><span> </span><br><span>                  m_llc.append_frame(data + frame->offset, frame->length);</span><br><span style="color: hsl(0, 100%, 40%);">-                  m_llc.consume(frame->length);</span><br><span style="color: hsl(120, 100%, 40%);">+                      llc_consume(&m_llc, frame->length);</span><br><span>           }</span><br><span> </span><br><span>                if (frame->is_complete) {</span><br><span>                         /* send frame to SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGPTBFUL(this, LOGL_DEBUG, "complete UL frame len=%d\n", m_llc.frame_length());</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGPTBFUL(this, LOGL_DEBUG, "complete UL frame len=%d\n", llc_frame_length(&m_llc));</span><br><span>                   snd_ul_ud();</span><br><span style="color: hsl(0, 100%, 40%);">-                    bts->do_rate_ctr_add(CTR_LLC_UL_BYTES, m_llc.frame_length());</span><br><span style="color: hsl(120, 100%, 40%);">+                      bts->do_rate_ctr_add(CTR_LLC_UL_BYTES, llc_frame_length(&m_llc));</span><br><span>                     m_llc.reset();</span><br><span>               }</span><br><span>    }</span><br><span>@@ -357,7 +357,7 @@</span><br><span> </span><br><span>  /* store measurement values */</span><br><span>       if (ms())</span><br><span style="color: hsl(0, 100%, 40%);">-               ms()->update_l1_meas(meas);</span><br><span style="color: hsl(120, 100%, 40%);">+                ms_update_l1_meas(ms(), meas);</span><br><span> </span><br><span>   uint32_t new_tlli = GSM_RESERVED_TMSI;</span><br><span>       unsigned int block_idx;</span><br><span>@@ -559,10 +559,10 @@</span><br><span> {</span><br><span>         uint8_t qos_profile[3];</span><br><span>      struct msgb *llc_pdu;</span><br><span style="color: hsl(0, 100%, 40%);">-   unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + m_llc.frame_length();</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + llc_frame_length(&m_llc);</span><br><span>        struct bssgp_bvc_ctx *bctx = gprs_bssgp_pcu_current_bctx();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] %s len=%d\n", tbf_name(this), m_llc.frame_length());</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] %s len=%d\n", tbf_name(this), llc_frame_length(&m_llc));</span><br><span>         if (!bctx) {</span><br><span>                 LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");</span><br><span>             m_llc.reset_frame_space();</span><br><span>@@ -570,8 +570,8 @@</span><br><span>     }</span><br><span> </span><br><span>        llc_pdu = msgb_alloc_headroom(msg_len, msg_len,"llc_pdu");</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t *buf = msgb_push(llc_pdu, TL16V_GROSS_LEN(sizeof(uint8_t)*m_llc.frame_length()));</span><br><span style="color: hsl(0, 100%, 40%);">-       tl16v_put(buf, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*m_llc.frame_length(), m_llc.frame);</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t *buf = msgb_push(llc_pdu, TL16V_GROSS_LEN(sizeof(uint8_t)*llc_frame_length(&m_llc)));</span><br><span style="color: hsl(120, 100%, 40%);">+     tl16v_put(buf, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*llc_frame_length(&m_llc), m_llc.frame);</span><br><span>         qos_profile[0] = QOS_PROFILE >> 16;</span><br><span>    qos_profile[1] = QOS_PROFILE >> 8;</span><br><span>     qos_profile[2] = QOS_PROFILE;</span><br><span>@@ -772,3 +772,11 @@</span><br><span> {</span><br><span>    return &m_window;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_ul_tbf *as_ul_tbf(struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    if (tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)</span><br><span style="color: hsl(120, 100%, 40%);">+           return static_cast<gprs_rlcmac_ul_tbf *>(tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/tbf_ul.h b/src/tbf_ul.h</span><br><span>index 9ccdf62..1d9cf50 100644</span><br><span>--- a/src/tbf_ul.h</span><br><span>+++ b/src/tbf_ul.h</span><br><span>@@ -108,32 +108,28 @@</span><br><span>         gprs_rlc_ul_window m_window;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef __cplusplus</span><br><span style="color: hsl(0, 100%, 40%);">-extern "C" {</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-void update_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, int8_t ta_delta);</span><br><span style="color: hsl(0, 100%, 40%);">-void set_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, uint8_t ta);</span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef __cplusplus</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> inline uint16_t gprs_rlcmac_ul_tbf::window_size() const</span><br><span> {</span><br><span>        return m_window.ws();</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-inline gprs_rlcmac_ul_tbf *as_ul_tbf(gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       if (tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)</span><br><span style="color: hsl(0, 100%, 40%);">-             return static_cast<gprs_rlcmac_ul_tbf *>(tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-    else</span><br><span style="color: hsl(0, 100%, 40%);">-            return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts, GprsMs *ms, int8_t use_trx, bool single_slot);</span><br><span> struct gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts, GprsMs *ms,</span><br><span>                                         int8_t use_trx, uint32_t tlli);</span><br><span> struct gprs_rlcmac_ul_tbf *handle_tbf_reject(struct gprs_rlcmac_bts *bts,</span><br><span>         GprsMs *ms, uint32_t tlli, uint8_t trx_no, uint8_t ts_no);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#else /* ifdef __cplusplus */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_ul_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+void update_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, int8_t ta_delta);</span><br><span style="color: hsl(120, 100%, 40%);">+void set_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, uint8_t ta);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_ul_tbf *as_ul_tbf(struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> #endif</span><br><span>diff --git a/tests/alloc/AllocTest.cpp b/tests/alloc/AllocTest.cpp</span><br><span>index 8ebf159..17cee46 100644</span><br><span>--- a/tests/alloc/AllocTest.cpp</span><br><span>+++ b/tests/alloc/AllocTest.cpp</span><br><span>@@ -224,12 +224,12 @@</span><br><span>          return false;</span><br><span> </span><br><span>    OSMO_ASSERT(ul_tbf->ms());</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ul_tbf->ms()->current_trx());</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_current_trx(ul_tbf->ms()));</span><br><span> </span><br><span>    dump_assignment(ul_tbf, "UL", verbose);</span><br><span> </span><br><span>        /* assume final ack has not been sent */</span><br><span style="color: hsl(0, 100%, 40%);">-        dl_tbf = tbf_alloc_dl_tbf(bts, ms, ms->current_trx()->trx_no, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   dl_tbf = tbf_alloc_dl_tbf(bts, ms, ms_current_trx(ms)->trx_no, false);</span><br><span>    if (!dl_tbf)</span><br><span>                 return false;</span><br><span> </span><br><span>@@ -268,11 +268,11 @@</span><br><span> </span><br><span>        dl_tbf->update_ms(0x23, GPRS_RLCMAC_DL_TBF);</span><br><span>      OSMO_ASSERT(dl_tbf->ms() == ms);</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_ASSERT(dl_tbf->ms()->current_trx());</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_current_trx(dl_tbf->ms()));</span><br><span> </span><br><span>    dump_assignment(dl_tbf, "DL", verbose);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ul_tbf = tbf_alloc_ul_tbf(bts, ms, ms->current_trx()->trx_no, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   ul_tbf = tbf_alloc_ul_tbf(bts, ms, ms_current_trx(ms)->trx_no, false);</span><br><span>    if (!ul_tbf)</span><br><span>                 return false;</span><br><span> </span><br><span>@@ -319,8 +319,8 @@</span><br><span>              return false;</span><br><span> </span><br><span>    OSMO_ASSERT(ul_tbf->ms() == ms);</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_ASSERT(ul_tbf->ms()->current_trx());</span><br><span style="color: hsl(0, 100%, 40%);">- trx_no = ms->current_trx()->trx_no;</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ms_current_trx(ul_tbf->ms()));</span><br><span style="color: hsl(120, 100%, 40%);">+ trx_no = ms_current_trx(ms)->trx_no;</span><br><span>      dump_assignment(ul_tbf, "UL", true);</span><br><span> </span><br><span>   /* assume final ack has not been sent */</span><br><span>@@ -453,50 +453,55 @@</span><br><span>     }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static GprsMs *alloc_tbfs(BTS *the_bts, GprsMs *ms, enum test_mode mode)</span><br><span style="color: hsl(120, 100%, 40%);">+static GprsMs *alloc_tbfs(BTS *the_bts, struct GprsMs *old_ms, enum test_mode mode)</span><br><span> {</span><br><span>         struct gprs_rlcmac_bts *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct GprsMs *ms, *new_ms;</span><br><span>  uint8_t trx_no = -1;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(old_ms != NULL);</span><br><span> </span><br><span>     bts = the_bts->bts_data();</span><br><span> </span><br><span>    gprs_rlcmac_tbf *tbf = NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        if (ms && ms->current_trx())</span><br><span style="color: hsl(0, 100%, 40%);">-         trx_no = ms->current_trx()->trx_no;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ms_current_trx(old_ms))</span><br><span style="color: hsl(120, 100%, 40%);">+           trx_no = ms_current_trx(old_ms)->trx_no;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- GprsMs::Guard guard1(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+     ms_ref(old_ms);</span><br><span> </span><br><span>  /* Allocate what is needed first */</span><br><span>  switch (mode) {</span><br><span>      case TEST_MODE_UL_ONLY:</span><br><span>      case TEST_MODE_DL_AFTER_UL:</span><br><span>  case TEST_MODE_UL_AND_DL:</span><br><span style="color: hsl(0, 100%, 40%);">-               if (ms->ul_tbf())</span><br><span style="color: hsl(0, 100%, 40%);">-                    tbf_free(ms->ul_tbf());</span><br><span style="color: hsl(0, 100%, 40%);">-              tbf = tbf_alloc_ul_tbf(bts, ms, trx_no, false);</span><br><span style="color: hsl(0, 100%, 40%);">-         if (tbf == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ms_ul_tbf(old_ms))</span><br><span style="color: hsl(120, 100%, 40%);">+                        tbf_free(ms_ul_tbf(old_ms));</span><br><span style="color: hsl(120, 100%, 40%);">+          tbf = tbf_alloc_ul_tbf(bts, old_ms, trx_no, false);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (tbf == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms_unref(old_ms);</span><br><span>                    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>            break;</span><br><span>       case TEST_MODE_DL_ONLY:</span><br><span>      case TEST_MODE_UL_AFTER_DL:</span><br><span>  case TEST_MODE_DL_AND_UL:</span><br><span style="color: hsl(0, 100%, 40%);">-               if (ms->dl_tbf())</span><br><span style="color: hsl(0, 100%, 40%);">-                    tbf_free(ms->dl_tbf());</span><br><span style="color: hsl(0, 100%, 40%);">-              tbf = tbf_alloc_dl_tbf(bts, ms, trx_no, false);</span><br><span style="color: hsl(0, 100%, 40%);">-         if (tbf == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ms_dl_tbf(old_ms))</span><br><span style="color: hsl(120, 100%, 40%);">+                        tbf_free(ms_dl_tbf(old_ms));</span><br><span style="color: hsl(120, 100%, 40%);">+          tbf = tbf_alloc_dl_tbf(bts, old_ms, trx_no, false);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (tbf == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ms_unref(old_ms);</span><br><span>                    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>    }</span><br><span> </span><br><span>        OSMO_ASSERT(tbf);</span><br><span>    OSMO_ASSERT(tbf->ms());</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms == NULL || ms == tbf->ms());</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(old_ms == tbf->ms());</span><br><span>         ms = tbf->ms();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  GprsMs::Guard guard2(ms);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+     ms_ref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+   new_ms = ms;</span><br><span>         /* Continue with what is needed next */</span><br><span>      switch (mode) {</span><br><span>      case TEST_MODE_UL_ONLY:</span><br><span>@@ -506,12 +511,12 @@</span><br><span> </span><br><span>  case TEST_MODE_DL_AFTER_UL:</span><br><span>  case TEST_MODE_UL_AND_DL:</span><br><span style="color: hsl(0, 100%, 40%);">-               ms = alloc_tbfs(the_bts, ms, TEST_MODE_DL_ONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+              new_ms = alloc_tbfs(the_bts, ms, TEST_MODE_DL_ONLY);</span><br><span>                 break;</span><br><span> </span><br><span>   case TEST_MODE_UL_AFTER_DL:</span><br><span>  case TEST_MODE_DL_AND_UL:</span><br><span style="color: hsl(0, 100%, 40%);">-               ms = alloc_tbfs(the_bts, ms, TEST_MODE_UL_ONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+              new_ms = alloc_tbfs(the_bts, ms, TEST_MODE_UL_ONLY);</span><br><span>                 break;</span><br><span>       }</span><br><span> </span><br><span>@@ -527,10 +532,12 @@</span><br><span>                break;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!ms && tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!new_ms && tbf)</span><br><span>          tbf_free(tbf);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      return  guard2.is_idle() ? NULL : ms;</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_unref(old_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+     ms_unref(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+ return new_ms;</span><br><span> }</span><br><span> </span><br><span> static unsigned alloc_many_tbfs(BTS *the_bts, unsigned min_class,</span><br><span>@@ -556,16 +563,16 @@</span><br><span>                 ms = the_bts->ms_by_tlli(tlli);</span><br><span>           if (!ms)</span><br><span>                     ms = the_bts->ms_alloc(0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                ms->set_ms_class(ms_class);</span><br><span style="color: hsl(120, 100%, 40%);">+                ms_set_ms_class(ms, ms_class);</span><br><span>               ms = alloc_tbfs(the_bts, ms, mode);</span><br><span>          if (!ms)</span><br><span>                     break;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              ms->set_tlli(tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+                ms_set_tlli(ms, tlli);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              ul_tbf = ms->ul_tbf();</span><br><span style="color: hsl(0, 100%, 40%);">-               dl_tbf = ms->dl_tbf();</span><br><span style="color: hsl(0, 100%, 40%);">-               trx = ms->current_trx();</span><br><span style="color: hsl(120, 100%, 40%);">+           ul_tbf = ms_ul_tbf(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+               dl_tbf = ms_dl_tbf(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+               trx = ms_current_trx(ms);</span><br><span> </span><br><span>                OSMO_ASSERT(ul_tbf || dl_tbf);</span><br><span> </span><br><span>@@ -616,12 +623,12 @@</span><br><span>                   get_dir_char(0x80, ul_slots, dl_slots, busy_slots));</span><br><span> </span><br><span>             if (tfi >= 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      OSMO_ASSERT(ms->current_trx());</span><br><span style="color: hsl(120, 100%, 40%);">+                    OSMO_ASSERT(ms_current_trx(ms));</span><br><span>                     tfi2 = the_bts->tfi_find_free(dir, &trx_no2,</span><br><span style="color: hsl(0, 100%, 40%);">-                             ms->current_trx()->trx_no);</span><br><span style="color: hsl(120, 100%, 40%);">+                             ms_current_trx(ms)->trx_no);</span><br><span>                      OSMO_ASSERT(tfi != tfi2);</span><br><span>                    OSMO_ASSERT(tfi2 < 0 ||</span><br><span style="color: hsl(0, 100%, 40%);">-                              trx_no2 == ms->current_trx()->trx_no);</span><br><span style="color: hsl(120, 100%, 40%);">+                          trx_no2 == ms_current_trx(ms)->trx_no);</span><br><span>           }</span><br><span> </span><br><span>                ms_class += 1;</span><br><span>diff --git a/tests/app_info/AppInfoTest.cpp b/tests/app_info/AppInfoTest.cpp</span><br><span>index cd4454d..6e33538 100644</span><br><span>--- a/tests/app_info/AppInfoTest.cpp</span><br><span>+++ b/tests/app_info/AppInfoTest.cpp</span><br><span>@@ -152,9 +152,9 @@</span><br><span> {</span><br><span>       fprintf(stderr, "--- %s ---\n",  __func__);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     tbf_free(tbf1);</span><br><span style="color: hsl(120, 100%, 40%);">+       tbf_free(tbf2);</span><br><span>      BTS::main_bts()->cleanup();</span><br><span style="color: hsl(0, 100%, 40%);">-  talloc_free(tbf1);</span><br><span style="color: hsl(0, 100%, 40%);">-      talloc_free(tbf2);</span><br><span>   /* FIXME: talloc report disabled, because bts->ms_alloc() in prepare_bts_with_two_dl_tbf_subscr() causes leak */</span><br><span>  /* talloc_report_full(tall_pcu_ctx, stderr); */</span><br><span>      talloc_free(tall_pcu_ctx);</span><br><span>diff --git a/tests/app_info/AppInfoTest.err b/tests/app_info/AppInfoTest.err</span><br><span>index ae20ea3..9b0910f 100644</span><br><span>--- a/tests/app_info/AppInfoTest.err</span><br><span>+++ b/tests/app_info/AppInfoTest.err</span><br><span>@@ -52,3 +52,14 @@</span><br><span> Sending Packet Application Information to 2 subscribers with active TBF</span><br><span> </span><br><span> --- cleanup ---</span><br><span style="color: hsl(120, 100%, 40%);">+PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 1 TBFs, USFs = 00, TFIs = 00000002.</span><br><span style="color: hsl(120, 100%, 40%);">+PDCH(TS 5, TRX 0): Detaching TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 1 TBFs, USFs = 00, TFIs = 00000002.</span><br><span style="color: hsl(120, 100%, 40%);">+PDCH(TS 6, TRX 0): Detaching TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 1 TBFs, USFs = 00, TFIs = 00000002.</span><br><span style="color: hsl(120, 100%, 40%);">+PDCH(TS 7, TRX 0): Detaching TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000.</span><br><span style="color: hsl(120, 100%, 40%);">+Detaching TBF from MS object, TLLI = 0xffffffff, TBF = TBF(TFI=0 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS)</span><br><span style="color: hsl(120, 100%, 40%);">+PDCH(TS 4, TRX 0): Detaching TBF(TFI=1 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000.</span><br><span style="color: hsl(120, 100%, 40%);">+PDCH(TS 5, TRX 0): Detaching TBF(TFI=1 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000.</span><br><span style="color: hsl(120, 100%, 40%);">+PDCH(TS 6, TRX 0): Detaching TBF(TFI=1 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS), 0 TBFs, USFs = 00, TFIs = 00000000.</span><br><span style="color: hsl(120, 100%, 40%);">+Detaching TBF from MS object, TLLI = 0xffffffff, TBF = TBF(TFI=1 TLLI=0xffffffff DIR=DL STATE=RELEASING EGPRS)</span><br><span style="color: hsl(120, 100%, 40%);">+Destroying MS object, TLLI = 0xffffffff</span><br><span style="color: hsl(120, 100%, 40%);">+Destroying MS object, TLLI = 0xffffffff</span><br><span>diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp</span><br><span>index 67ed2a7..8fa76dd 100644</span><br><span>--- a/tests/edge/EdgeTest.cpp</span><br><span>+++ b/tests/edge/EdgeTest.cpp</span><br><span>@@ -619,7 +619,7 @@</span><br><span>         write_offset = 0;</span><br><span>    memset(data, 0, sizeof(data));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(llc.chunk_size() == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(llc_chunk_size(&llc) == 1);</span><br><span> </span><br><span>      count_payload = -1;</span><br><span> </span><br><span>@@ -767,7 +767,7 @@</span><br><span>        write_offset = 0;</span><br><span>    memset(data, 0, sizeof(data));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(llc.chunk_size() == 10);</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(llc_chunk_size(&llc) == 10);</span><br><span>         count_payload = -1;</span><br><span> </span><br><span>      ar = Encoding::rlc_data_to_dl_append(&rdbi, cs,</span><br><span>@@ -899,7 +899,7 @@</span><br><span>    write_offset = 0;</span><br><span>    memset(data, 0, sizeof(data));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(llc.chunk_size() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(llc_chunk_size(&llc) == 0);</span><br><span>  count_payload = -1;</span><br><span> </span><br><span>      ar = Encoding::rlc_data_to_dl_append(&rdbi, cs,</span><br><span>@@ -1167,7 +1167,6 @@</span><br><span>  uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta,</span><br><span>    uint8_t ms_class)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct pcu_l1_meas meas;</span><br><span>     int tfi = 0;</span><br><span>         uint8_t data[79] = {0};</span><br><span>      struct gprs_rlc_ul_header_egprs_2 *egprs2  = NULL;</span><br><span>diff --git a/tests/llc/LlcTest.cpp b/tests/llc/LlcTest.cpp</span><br><span>index 10cd96b..bfcac77 100644</span><br><span>--- a/tests/llc/LlcTest.cpp</span><br><span>+++ b/tests/llc/LlcTest.cpp</span><br><span>@@ -60,10 +60,10 @@</span><br><span> }</span><br><span> </span><br><span> static void dequeue_and_check(gprs_llc_queue *queue, const uint8_t *exp_data,</span><br><span style="color: hsl(0, 100%, 40%);">-     size_t len, const gprs_llc_queue::MetaInfo *exp_info)</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t len, const MetaInfo *exp_info)</span><br><span> {</span><br><span>   struct msgb *llc_msg;</span><br><span style="color: hsl(0, 100%, 40%);">-   const gprs_llc_queue::MetaInfo *info_res;</span><br><span style="color: hsl(120, 100%, 40%);">+     const MetaInfo *info_res;</span><br><span> </span><br><span>        llc_msg = queue->dequeue(&info_res);</span><br><span>  OSMO_ASSERT(llc_msg != NULL);</span><br><span>@@ -88,7 +88,7 @@</span><br><span> }</span><br><span> </span><br><span> static void dequeue_and_check(gprs_llc_queue *queue, const char *exp_message,</span><br><span style="color: hsl(0, 100%, 40%);">-     const gprs_llc_queue::MetaInfo *exp_info = 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ const MetaInfo *exp_info = 0)</span><br><span> {</span><br><span>   dequeue_and_check(queue,</span><br><span>             (uint8_t *)(exp_message), strlen(exp_message), exp_info);</span><br><span>@@ -101,33 +101,33 @@</span><br><span> </span><br><span>        printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   queue.init();</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(queue.size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     llc_queue_init(&queue);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(llc_queue_size(&queue) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 0);</span><br><span> </span><br><span>  enqueue_data(&queue, "LLC message", &expire_time);</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(queue.size() == 1);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 11);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(&queue) == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 11);</span><br><span> </span><br><span>         enqueue_data(&queue, "other LLC message", &expire_time);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(queue.size() == 2);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 28);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(&queue) == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 28);</span><br><span> </span><br><span>         dequeue_and_check(&queue, "LLC message");</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.size() == 1);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 17);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(&queue) == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 17);</span><br><span> </span><br><span>         dequeue_and_check(&queue, "other LLC message");</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(queue.size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(llc_queue_size(&queue) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 0);</span><br><span> </span><br><span>  enqueue_data(&queue, "LLC",  &expire_time);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(queue.size() == 1);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(llc_queue_size(&queue) == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 3);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     queue.clear(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(queue.size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     llc_queue_clear(&queue, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(&queue) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 0);</span><br><span> </span><br><span>  printf("=== end %s ===\n", __func__);</span><br><span> }</span><br><span>@@ -135,14 +135,14 @@</span><br><span> static void test_llc_meta()</span><br><span> {</span><br><span>     gprs_llc_queue queue;</span><br><span style="color: hsl(0, 100%, 40%);">-   gprs_llc_queue::MetaInfo info1 = {0};</span><br><span style="color: hsl(0, 100%, 40%);">-   gprs_llc_queue::MetaInfo info2 = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+ MetaInfo info1 = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+ MetaInfo info2 = {0};</span><br><span> </span><br><span>    printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   queue.init();</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(queue.size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     llc_queue_init(&queue);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(llc_queue_size(&queue) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 0);</span><br><span> </span><br><span>  info1.recv_time.tv_sec = 123456777;</span><br><span>  info1.recv_time.tv_nsec = 123456000;</span><br><span>@@ -161,9 +161,9 @@</span><br><span>   dequeue_and_check(&queue, "LLC message 1", &info1);</span><br><span>        dequeue_and_check(&queue, "LLC message 2", &info2);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       queue.clear(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(queue.size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue.octets() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     llc_queue_clear(&queue, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(&queue) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(llc_queue_octets(&queue) == 0);</span><br><span> </span><br><span>  printf("=== end %s ===\n", __func__);</span><br><span> }</span><br><span>@@ -176,8 +176,8 @@</span><br><span> </span><br><span>       printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   queue1.init();</span><br><span style="color: hsl(0, 100%, 40%);">-  queue2.init();</span><br><span style="color: hsl(120, 100%, 40%);">+        llc_queue_init(&queue1);</span><br><span style="color: hsl(120, 100%, 40%);">+  llc_queue_init(&queue2);</span><br><span> </span><br><span>     clk_mono_override_time->tv_sec += 1;</span><br><span>      enqueue_data(&queue1, "*A*", &expire_time);</span><br><span>@@ -194,17 +194,17 @@</span><br><span>        clk_mono_override_time->tv_sec += 1;</span><br><span>      enqueue_data(&queue2, "*E*", &expire_time);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(queue1.size() == 3);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(queue1.octets() == 9);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(queue2.size() == 2);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(queue2.octets() == 6);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(&queue1) == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(llc_queue_octets(&queue1) == 9);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(llc_queue_size(&queue2) == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(llc_queue_octets(&queue2) == 6);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    queue2.move_and_merge(&queue1);</span><br><span style="color: hsl(120, 100%, 40%);">+   llc_queue_move_and_merge(&queue2, &queue1);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(queue1.size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(queue1.octets() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(queue2.size() == 5);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(queue2.octets() == 15);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(llc_queue_size(&queue1) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(llc_queue_octets(&queue1) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(llc_queue_size(&queue2) == 5);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(llc_queue_octets(&queue2) == 15);</span><br><span> </span><br><span>        dequeue_and_check(&queue2, "*A*");</span><br><span>     dequeue_and_check(&queue2, "*B*");</span><br><span>@@ -212,8 +212,8 @@</span><br><span>       dequeue_and_check(&queue2, "*D*");</span><br><span>     dequeue_and_check(&queue2, "*E*");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(queue2.size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(queue2.octets() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(&queue2) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(llc_queue_octets(&queue2) == 0);</span><br><span> </span><br><span>         printf("=== end %s ===\n", __func__);</span><br><span> }</span><br><span>diff --git a/tests/ms/MsTest.cpp b/tests/ms/MsTest.cpp</span><br><span>index 4f47bc9..c164409 100644</span><br><span>--- a/tests/ms/MsTest.cpp</span><br><span>+++ b/tests/ms/MsTest.cpp</span><br><span>@@ -56,33 +56,33 @@</span><br><span> </span><br><span>      printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ms = new GprsMs(&the_bts, tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(120, 100%, 40%);">+        ms = ms_alloc(&the_bts, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(ms_is_idle(ms));</span><br><span> </span><br><span>     dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);</span><br><span>       new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms);</span><br><span>   ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);</span><br><span>       new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  ms->attach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->dl_tbf() == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_attach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_dl_tbf(ms) == NULL);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->attach_tbf(dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->dl_tbf() == dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       ms_attach_tbf(ms, dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->tbf(GPRS_RLCMAC_UL_TBF) == ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms->tbf(GPRS_RLCMAC_DL_TBF) == dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ms_tbf(ms, GPRS_RLCMAC_UL_TBF) == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ms_tbf(ms, GPRS_RLCMAC_DL_TBF) == dl_tbf);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      ms->detach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       ms_detach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       ms->detach_tbf(dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_detach_tbf(ms, dl_tbf);</span><br><span>   /* The ms object is freed now */</span><br><span>     ms = NULL;</span><br><span> </span><br><span>@@ -92,6 +92,23 @@</span><br><span>  printf("=== end %s ===\n", __func__);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static enum {CB_UNKNOWN, CB_IS_IDLE, CB_IS_ACTIVE} last_cb = CB_UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_idle_cb(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("  ms_idle() was called\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ last_cb = CB_IS_IDLE;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_active_cb(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("  ms_active() was called\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       last_cb = CB_IS_ACTIVE;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gpr_ms_callback ms_cb = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .ms_idle = ms_idle_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+        .ms_active = ms_active_cb</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span> static void test_ms_callback()</span><br><span> {</span><br><span>         uint32_t tlli = 0xffeeddbb;</span><br><span>@@ -99,63 +116,50 @@</span><br><span>   gprs_rlcmac_ul_tbf *ul_tbf;</span><br><span>  BTS the_bts;</span><br><span>         GprsMs *ms;</span><br><span style="color: hsl(0, 100%, 40%);">-     static enum {UNKNOWN, IS_IDLE, IS_ACTIVE} last_cb = UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    struct MyCallback: public GprsMs::Callback {</span><br><span style="color: hsl(0, 100%, 40%);">-            virtual void ms_idle(class GprsMs *ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-                  printf("  ms_idle() was called\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                   last_cb = IS_IDLE;</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-               virtual void ms_active(class GprsMs *ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-                 printf("  ms_active() was called\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                 last_cb = IS_ACTIVE;</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(0, 100%, 40%);">-       } cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ last_cb = CB_UNKNOWN;</span><br><span> </span><br><span>    printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ms = new GprsMs(&the_bts, tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_callback(&cb);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms = ms_alloc(&the_bts, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_set_callback(ms, &ms_cb);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ms_is_idle(ms));</span><br><span> </span><br><span>     dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);</span><br><span>       new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms);</span><br><span>   ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);</span><br><span>       new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(last_cb == UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(last_cb == CB_UNKNOWN);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->attach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->dl_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(last_cb == IS_ACTIVE);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_dl_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(last_cb == CB_IS_ACTIVE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       last_cb = UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+    last_cb = CB_UNKNOWN;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       ms->attach_tbf(dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->dl_tbf() == dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(last_cb == UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_attach_tbf(ms, dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(last_cb == CB_UNKNOWN);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->detach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(last_cb == UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_detach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(last_cb == CB_UNKNOWN);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->detach_tbf(dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms->ul_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(last_cb == IS_IDLE);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_detach_tbf(ms, dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_ul_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ms_dl_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(last_cb == CB_IS_IDLE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- last_cb = UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-      delete ms;</span><br><span style="color: hsl(120, 100%, 40%);">+    last_cb = CB_UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(ms);</span><br><span> </span><br><span>         talloc_free(dl_tbf);</span><br><span>         talloc_free(ul_tbf);</span><br><span>@@ -163,6 +167,22 @@</span><br><span>  printf("=== end %s ===\n", __func__);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static bool was_idle;</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_replace_tbf_idle_cb(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("  ms_idle() was called\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ was_idle = true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void ms_replace_tbf_active_cb(struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("  ms_active() was called\n");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gpr_ms_callback ms_replace_tbf_cb = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .ms_idle = ms_replace_tbf_idle_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+    .ms_active = ms_replace_tbf_active_cb</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span> static void test_ms_replace_tbf()</span><br><span> {</span><br><span>  uint32_t tlli = 0xffeeddbb;</span><br><span>@@ -170,26 +190,13 @@</span><br><span>  gprs_rlcmac_ul_tbf *ul_tbf;</span><br><span>  BTS the_bts;</span><br><span>         GprsMs *ms;</span><br><span style="color: hsl(0, 100%, 40%);">-     static bool was_idle;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   struct MyCallback: public GprsMs::Callback {</span><br><span style="color: hsl(0, 100%, 40%);">-            virtual void ms_idle(class GprsMs *ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-                  printf("  ms_idle() was called\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                   was_idle = true;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-               virtual void ms_active(class GprsMs *ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-                 printf("  ms_active() was called\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-       } cb;</span><br><span> </span><br><span>    printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ms = new GprsMs(&the_bts, tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_callback(&cb);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms = ms_alloc(&the_bts, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_set_callback(ms, &ms_replace_tbf_cb);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ms_is_idle(ms));</span><br><span>         was_idle = false;</span><br><span> </span><br><span>        dl_tbf[0] = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);</span><br><span>@@ -199,49 +206,49 @@</span><br><span>    ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);</span><br><span>       new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  ms->attach_tbf(dl_tbf[0]);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == dl_tbf[0]);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(llist_empty(&ms->old_tbfs()));</span><br><span style="color: hsl(120, 100%, 40%);">+     ms_attach_tbf(ms, dl_tbf[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(llist_empty(&ms->old_tbfs));</span><br><span>      OSMO_ASSERT(!was_idle);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms->attach_tbf(dl_tbf[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!llist_empty(&ms->old_tbfs()));</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(ms, dl_tbf[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(!llist_empty(&ms->old_tbfs));</span><br><span>     OSMO_ASSERT(!was_idle);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms->attach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!llist_empty(&ms->old_tbfs()));</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(!llist_empty(&ms->old_tbfs));</span><br><span>     OSMO_ASSERT(!was_idle);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms->detach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!llist_empty(&ms->old_tbfs()));</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_detach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(!llist_empty(&ms->old_tbfs));</span><br><span>     OSMO_ASSERT(!was_idle);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms->detach_tbf(dl_tbf[0]);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(llist_empty(&ms->old_tbfs()));</span><br><span style="color: hsl(120, 100%, 40%);">+     ms_detach_tbf(ms, dl_tbf[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(llist_empty(&ms->old_tbfs));</span><br><span>      OSMO_ASSERT(!was_idle);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms->detach_tbf(dl_tbf[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms->ul_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(llist_empty(&ms->old_tbfs()));</span><br><span style="color: hsl(120, 100%, 40%);">+     ms_detach_tbf(ms, dl_tbf[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_ul_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ms_dl_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(llist_empty(&ms->old_tbfs));</span><br><span>      OSMO_ASSERT(was_idle);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      delete ms;</span><br><span style="color: hsl(120, 100%, 40%);">+    talloc_free(ms);</span><br><span> </span><br><span>         talloc_free(dl_tbf[0]);</span><br><span>      talloc_free(dl_tbf[1]);</span><br><span>@@ -260,86 +267,86 @@</span><br><span> </span><br><span>  printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ms = new GprsMs(&the_bts, start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms = ms_alloc(&the_bts, start_tlli);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ms_is_idle(ms));</span><br><span> </span><br><span>     /* MS announces TLLI, SGSN uses it immediately */</span><br><span style="color: hsl(0, 100%, 40%);">-       ms->set_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_set_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->confirm_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(!ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_confirm_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(!ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span>     /* MS announces TLLI, SGSN uses it later */</span><br><span style="color: hsl(0, 100%, 40%);">-     ms->set_tlli(start_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->confirm_tlli(start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_tlli(ms, start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_confirm_tlli(ms, start_tlli);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_set_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->confirm_tlli(start_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_confirm_tlli(ms, start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->set_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_set_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->confirm_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(!ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_confirm_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(!ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span>     /* MS announces TLLI, SGSN uses it later after another new TLLI */</span><br><span style="color: hsl(0, 100%, 40%);">-      ms->set_tlli(start_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->confirm_tlli(start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_tlli(ms, start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_confirm_tlli(ms, start_tlli);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_set_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->confirm_tlli(other_sgsn_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->check_tlli(other_sgsn_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_confirm_tlli(ms, other_sgsn_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_check_tlli(ms, other_sgsn_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->check_tlli(other_sgsn_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_check_tlli(ms, other_sgsn_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ms->confirm_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(!ms->check_tlli(start_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(!ms->check_tlli(other_sgsn_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+     ms_confirm_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(!ms_check_tlli(ms, start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(!ms_check_tlli(ms, other_sgsn_tlli));</span><br><span> </span><br><span>        /* SGSN uses the new TLLI before it is announced by the MS (shouldn't</span><br><span>     * happen in normal use) */</span><br><span style="color: hsl(0, 100%, 40%);">-     ms->set_tlli(start_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->confirm_tlli(start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_tlli(ms, start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_confirm_tlli(ms, start_tlli);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ms->confirm_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->tlli() == start_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_confirm_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ms_tlli(ms) == start_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->set_tlli(new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->tlli() == new_ms_tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->check_tlli(new_ms_tlli));</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(!ms->check_tlli(start_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  ms_set_tlli(ms, new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_tlli(ms) == new_ms_tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_check_tlli(ms, new_ms_tlli));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(!ms_check_tlli(ms, start_tlli));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        delete ms;</span><br><span style="color: hsl(120, 100%, 40%);">+    talloc_free(ms);</span><br><span> </span><br><span>         printf("=== end %s ===\n", __func__);</span><br><span> }</span><br><span>@@ -353,9 +360,9 @@</span><br><span>   ms = st->create_ms();</span><br><span> </span><br><span>         if (dir == GPRS_RLCMAC_UL_TBF)</span><br><span style="color: hsl(0, 100%, 40%);">-          ms->set_tlli(tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+                ms_set_tlli(ms, tlli);</span><br><span>       else</span><br><span style="color: hsl(0, 100%, 40%);">-            ms->confirm_tlli(tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+            ms_confirm_tlli(ms, tlli);</span><br><span> </span><br><span>       return ms;</span><br><span> }</span><br><span>@@ -378,44 +385,44 @@</span><br><span> </span><br><span>  ms = prepare_ms(&store, tlli + 0, GPRS_RLCMAC_UL_TBF);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->tlli() == tlli + 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ms->set_imsi(imsi1);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(strcmp(ms->imsi(), imsi1) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_tlli(ms) == tlli + 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_set_imsi(ms, imsi1);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(strcmp(ms_imsi(ms), imsi1) == 0);</span><br><span> </span><br><span>    ms_tmp = store.get_ms(tlli + 0);</span><br><span>     OSMO_ASSERT(ms == ms_tmp);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->tlli() == tlli + 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_tlli(ms) == tlli + 0);</span><br><span> </span><br><span>    ms_tmp = store.get_ms(0, 0, imsi1);</span><br><span>  OSMO_ASSERT(ms == ms_tmp);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(strcmp(ms->imsi(), imsi1) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(strcmp(ms_imsi(ms), imsi1) == 0);</span><br><span>        ms_tmp = store.get_ms(0, 0, imsi2);</span><br><span>  OSMO_ASSERT(ms_tmp == NULL);</span><br><span> </span><br><span>     ms = prepare_ms(&store, tlli + 1, GPRS_RLCMAC_UL_TBF);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->tlli() == tlli + 1);</span><br><span style="color: hsl(0, 100%, 40%);">- ms->set_imsi(imsi2);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(strcmp(ms->imsi(), imsi2) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_tlli(ms) == tlli + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_set_imsi(ms, imsi2);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(strcmp(ms_imsi(ms), imsi2) == 0);</span><br><span> </span><br><span>    ms_tmp = store.get_ms(tlli + 1);</span><br><span>     OSMO_ASSERT(ms == ms_tmp);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->tlli() == tlli + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_tlli(ms) == tlli + 1);</span><br><span> </span><br><span>    ms_tmp = store.get_ms(0, 0, imsi1);</span><br><span>  OSMO_ASSERT(ms_tmp != NULL);</span><br><span>         OSMO_ASSERT(ms_tmp != ms);</span><br><span>   ms_tmp = store.get_ms(0, 0, imsi2);</span><br><span>  OSMO_ASSERT(ms == ms_tmp);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(strcmp(ms->imsi(), imsi2) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(strcmp(ms_imsi(ms), imsi2) == 0);</span><br><span> </span><br><span>    /* delete ms */</span><br><span>      ms = store.get_ms(tlli + 0);</span><br><span>         OSMO_ASSERT(ms != NULL);</span><br><span>     ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);</span><br><span>       new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);</span><br><span style="color: hsl(0, 100%, 40%);">-      ms->attach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      ms->detach_tbf(ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_detach_tbf(ms, ul_tbf);</span><br><span>   ms = store.get_ms(tlli + 0);</span><br><span>         OSMO_ASSERT(ms == NULL);</span><br><span>     ms = store.get_ms(tlli + 1);</span><br><span>@@ -424,8 +431,8 @@</span><br><span>   /* delete ms */</span><br><span>      ms = store.get_ms(tlli + 1);</span><br><span>         OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        ms->attach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      ms->detach_tbf(ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_detach_tbf(ms, ul_tbf);</span><br><span>   ms = store.get_ms(tlli + 1);</span><br><span>         OSMO_ASSERT(ms == NULL);</span><br><span> </span><br><span>@@ -441,62 +448,49 @@</span><br><span>         gprs_rlcmac_ul_tbf *ul_tbf;</span><br><span>  BTS the_bts;</span><br><span>         GprsMs *ms;</span><br><span style="color: hsl(0, 100%, 40%);">-     static enum {UNKNOWN, IS_IDLE, IS_ACTIVE} last_cb = UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    struct MyCallback: public GprsMs::Callback {</span><br><span style="color: hsl(0, 100%, 40%);">-            virtual void ms_idle(class GprsMs *ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-                  printf("  ms_idle() was called\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                   last_cb = IS_IDLE;</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-               virtual void ms_active(class GprsMs *ms) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-                 printf("  ms_active() was called\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                 last_cb = IS_ACTIVE;</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(0, 100%, 40%);">-       } cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ last_cb = CB_UNKNOWN;</span><br><span> </span><br><span>    printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ms = new GprsMs(&the_bts, tlli);</span><br><span style="color: hsl(0, 100%, 40%);">-    ms->set_callback(&cb);</span><br><span style="color: hsl(0, 100%, 40%);">-   ms->set_timeout(1);</span><br><span style="color: hsl(120, 100%, 40%);">+        ms = ms_alloc(&the_bts, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_set_callback(ms, &ms_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_timeout(ms, 1);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ms_is_idle(ms));</span><br><span> </span><br><span>     dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);</span><br><span>       new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms);</span><br><span>   ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);</span><br><span>       new (ul_tbf) gprs_rlcmac_ul_tbf(&the_bts, ms);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(last_cb == UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(last_cb == CB_UNKNOWN);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->attach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(last_cb == IS_ACTIVE);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(last_cb == CB_IS_ACTIVE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       last_cb = UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+    last_cb = CB_UNKNOWN;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       ms->attach_tbf(dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(last_cb == UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_attach_tbf(ms, dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(last_cb == CB_UNKNOWN);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->detach_tbf(ul_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(last_cb == UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_detach_tbf(ms, ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(last_cb == CB_UNKNOWN);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms->detach_tbf(dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(last_cb == UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_detach_tbf(ms, dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(last_cb == CB_UNKNOWN);</span><br><span> </span><br><span>      usleep(1100000);</span><br><span>     osmo_timers_update();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(last_cb == IS_IDLE);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_is_idle(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(last_cb == CB_IS_IDLE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- last_cb = UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-      delete ms;</span><br><span style="color: hsl(120, 100%, 40%);">+    last_cb = CB_UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(ms);</span><br><span>     talloc_free(dl_tbf);</span><br><span>         talloc_free(ul_tbf);</span><br><span> </span><br><span>@@ -519,21 +513,21 @@</span><br><span>     bts->cs_downgrade_threshold = 0;</span><br><span>  bts->cs_adj_lower_limit = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms = new GprsMs(&the_bts, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+  ms = ms_alloc(&the_bts, tlli);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms->is_idle());</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ms_is_idle(ms));</span><br><span> </span><br><span>     dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);</span><br><span>       new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms);</span><br><span style="color: hsl(0, 100%, 40%);">-      ms->attach_tbf(dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+    ms_attach_tbf(ms, dl_tbf);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(!ms->is_idle());</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(!ms_is_idle(ms));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(mcs_chan_code(ms->current_cs_dl()) == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(mcs_chan_code(ms_current_cs_dl(ms)) == 3);</span><br><span> </span><br><span>   bts->cs_downgrade_threshold = 200;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(mcs_chan_code(ms->current_cs_dl()) == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(mcs_chan_code(ms_current_cs_dl(ms)) == 2);</span><br><span> </span><br><span>   talloc_free(dl_tbf);</span><br><span> </span><br><span>@@ -543,10 +537,10 @@</span><br><span> static void dump_ms(const GprsMs *ms, const char *pref)</span><br><span> {</span><br><span>     printf("%s MS DL %s/%s, UL %s/%s, mode %s, <%s>\n", pref,</span><br><span style="color: hsl(0, 100%, 40%);">-              mcs_name(ms->current_cs_dl()), mcs_name(ms->max_cs_dl()),</span><br><span style="color: hsl(0, 100%, 40%);">-         mcs_name(ms->current_cs_ul()), mcs_name(ms->max_cs_ul()),</span><br><span style="color: hsl(0, 100%, 40%);">-         mode_name(ms->mode()),</span><br><span style="color: hsl(0, 100%, 40%);">-               ms->is_idle() ? "IDLE" : "ACTIVE");</span><br><span style="color: hsl(120, 100%, 40%);">+            mcs_name(ms_current_cs_dl(ms)), mcs_name(ms_max_cs_dl(ms)),</span><br><span style="color: hsl(120, 100%, 40%);">+           mcs_name(ms_current_cs_ul(ms)), mcs_name(ms_max_cs_ul(ms)),</span><br><span style="color: hsl(120, 100%, 40%);">+           mode_name(ms_mode(ms)),</span><br><span style="color: hsl(120, 100%, 40%);">+               ms_is_idle(ms) ? "IDLE" : "ACTIVE");</span><br><span> }</span><br><span> </span><br><span> static void test_ms_mcs_mode()</span><br><span>@@ -560,48 +554,48 @@</span><br><span> </span><br><span>       printf("=== start %s ===\n", __func__);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ms1 = new GprsMs(&the_bts, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms1 = ms_alloc(&the_bts, tlli);</span><br><span>  dump_ms(ms1, "1: no BTS defaults  ");</span><br><span> </span><br><span>  bts->initial_cs_dl = 4;</span><br><span>   bts->initial_cs_ul = 1;</span><br><span>   bts->cs_downgrade_threshold = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ms2 = new GprsMs(&the_bts, tlli + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ms2 = ms_alloc(&the_bts, tlli + 1);</span><br><span>      dump_ms(ms2, "2: with BTS defaults");</span><br><span> </span><br><span>  dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);</span><br><span>       new (dl_tbf) gprs_rlcmac_dl_tbf(&the_bts, ms2);</span><br><span style="color: hsl(0, 100%, 40%);">-     ms2->attach_tbf(dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_attach_tbf(ms2, dl_tbf);</span><br><span> </span><br><span>      dump_ms(ms2, "2: after TBF attach ");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms1->set_mode(EGPRS);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_mode(ms1, EGPRS);</span><br><span>     dump_ms(ms1, "1: after mode set   ");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms2->set_mode(EGPRS);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_mode(ms2, EGPRS);</span><br><span>     dump_ms(ms2, "2: after mode set   ");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms1->set_current_cs_dl(MCS7);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_current_cs_dl(ms1, MCS7);</span><br><span>     dump_ms(ms1, "1: after MCS set    ");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms2->set_current_cs_dl(MCS8);</span><br><span style="color: hsl(120, 100%, 40%);">+      ms_set_current_cs_dl(ms2, MCS8);</span><br><span>     dump_ms(ms2, "2: after MCS set    ");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms1->set_mode(EGPRS_GMSK);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_set_mode(ms1, EGPRS_GMSK);</span><br><span>        dump_ms(ms1, "1: after mode set   ");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms2->set_mode(EGPRS_GMSK);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_set_mode(ms2, EGPRS_GMSK);</span><br><span>        dump_ms(ms2, "2: after mode set   ");</span><br><span> </span><br><span>  // FIXME: following code triggers ASAN failure:</span><br><span>      // ms2->detach_tbf(dl_tbf);</span><br><span>       // dump_ms(ms2, "2: after TBF detach ");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  ms1->set_mode(GPRS);</span><br><span style="color: hsl(120, 100%, 40%);">+       ms_set_mode(ms1, GPRS);</span><br><span>      dump_ms(ms1, "1: after mode set   ");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ms2->set_mode(GPRS);</span><br><span style="color: hsl(120, 100%, 40%);">+       ms_set_mode(ms2, GPRS);</span><br><span>      dump_ms(ms2, "2: after mode set   ");</span><br><span> </span><br><span>  talloc_free(dl_tbf);</span><br><span>diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp</span><br><span>index 1a1dc6f..e6041a3 100644</span><br><span>--- a/tests/tbf/TbfTest.cpp</span><br><span>+++ b/tests/tbf/TbfTest.cpp</span><br><span>@@ -109,14 +109,14 @@</span><br><span>        OSMO_ASSERT(dl_tbf != NULL);</span><br><span>         dl_tbf->update_ms(0x2342, GPRS_RLCMAC_DL_TBF);</span><br><span>    dl_tbf->set_ta(4);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(ms->dl_tbf() == dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);</span><br><span>        OSMO_ASSERT(dl_tbf->ms() == ms);</span><br><span> </span><br><span>      gprs_rlcmac_tbf *ul_tbf = tbf_alloc_ul_tbf(the_bts.bts_data(),</span><br><span>                                                  ms, 0, false);</span><br><span>    OSMO_ASSERT(ul_tbf != NULL);</span><br><span>         ul_tbf->update_ms(0x2342, GPRS_RLCMAC_UL_TBF);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span>        OSMO_ASSERT(ul_tbf->ms() == ms);</span><br><span> </span><br><span>      OSMO_ASSERT(the_bts.ms_by_tlli(0x2342) == ms);</span><br><span>@@ -133,8 +133,8 @@</span><br><span> </span><br><span>     ms_new = the_bts.ms_by_tlli(0x4232);</span><br><span>         OSMO_ASSERT(ms == ms_new);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->dl_tbf() == dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_dl_tbf(ms) == dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span> </span><br><span>    /* Now use the new TLLI for UL */</span><br><span>    ul_tbf->update_ms(0x4232, GPRS_RLCMAC_UL_TBF);</span><br><span>@@ -143,7 +143,7 @@</span><br><span> </span><br><span>  ms_new = the_bts.ms_by_tlli(0x4232);</span><br><span>         OSMO_ASSERT(ms_new != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms_new->ta() == 4);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(ms_ta(ms_new) == 4);</span><br><span> </span><br><span>         OSMO_ASSERT(ul_tbf->ta() == 4);</span><br><span>   OSMO_ASSERT(dl_tbf->ta() == 4);</span><br><span>@@ -298,25 +298,27 @@</span><br><span> </span><br><span>       /* Clean up and ensure tbfs are in the correct state */</span><br><span>      OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE));</span><br><span style="color: hsl(0, 100%, 40%);">-     new_tbf = ms->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+    new_tbf = ms_dl_tbf(ms);</span><br><span>     check_tbf(new_tbf);</span><br><span>  OSMO_ASSERT(new_tbf != dl_tbf);</span><br><span>      OSMO_ASSERT(new_tbf->tfi() == 1);</span><br><span>         check_tbf(dl_tbf);</span><br><span>   TBF_SET_ASS_STATE_DL(dl_tbf, GPRS_RLCMAC_DL_ASS_NONE);</span><br><span>       if (test_mode == TEST_MODE_REVERSE_FREE) {</span><br><span style="color: hsl(0, 100%, 40%);">-              GprsMs::Guard guard(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_ref(ms);</span><br><span>          tbf_free(new_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-              OSMO_ASSERT(ms->dl_tbf() == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(ms_dl_tbf(ms) == NULL);</span><br><span>          check_tbf(dl_tbf);</span><br><span>           tbf_free(dl_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+             ms_unref(ms);</span><br><span>        } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                GprsMs::Guard guard(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+              ms_ref(ms);</span><br><span>          tbf_free(dl_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-               OSMO_ASSERT(ms->dl_tbf() == new_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(ms_dl_tbf(ms) == new_tbf);</span><br><span>               check_tbf(new_tbf);</span><br><span>          tbf_free(new_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-              OSMO_ASSERT(ms->dl_tbf() == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(ms_dl_tbf(ms) == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           ms_unref(ms);</span><br><span>        }</span><br><span> </span><br><span>        fprintf(stderr, "=== end %s ===\n", __func__);</span><br><span>@@ -421,32 +423,33 @@</span><br><span>     dl_tbf[0]->update_ms(0xf1000001, GPRS_RLCMAC_DL_TBF);</span><br><span>     dl_tbf[1]->update_ms(0xf1000002, GPRS_RLCMAC_DL_TBF);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    dl_tbf[0]->ms()->set_imsi("001001000000001");</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_set_imsi(dl_tbf[0]->ms(), "001001000000001");</span><br><span>        ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000001");</span><br><span>  OSMO_ASSERT(ms1 != NULL);</span><br><span>    ms2 = the_bts.ms_store().get_ms(0xf1000001);</span><br><span>         OSMO_ASSERT(ms2 != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(strcmp(ms2->imsi(), "001001000000001") == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(strcmp(ms_imsi(ms2), "001001000000001") == 0);</span><br><span>         OSMO_ASSERT(ms1 == ms2);</span><br><span> </span><br><span>         /* change the IMSI on TBF 0 */</span><br><span style="color: hsl(0, 100%, 40%);">-  dl_tbf[0]->ms()->set_imsi("001001000000002");</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_set_imsi(dl_tbf[0]->ms(), "001001000000002");</span><br><span>        ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000001");</span><br><span>  OSMO_ASSERT(ms1 == NULL);</span><br><span>    ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000002");</span><br><span>  OSMO_ASSERT(ms1 != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(strcmp(ms2->imsi(), "001001000000002") == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(strcmp(ms_imsi(ms2), "001001000000002") == 0);</span><br><span>         OSMO_ASSERT(ms1 == ms2);</span><br><span> </span><br><span>         /* use the same IMSI on TBF 1 */</span><br><span>     {</span><br><span style="color: hsl(0, 100%, 40%);">-               GprsMs::Guard guard(ms2);</span><br><span style="color: hsl(0, 100%, 40%);">-               dl_tbf[1]->ms()->set_imsi("001001000000002");</span><br><span style="color: hsl(120, 100%, 40%);">+         ms_ref(ms2);</span><br><span style="color: hsl(120, 100%, 40%);">+          ms_set_imsi(dl_tbf[1]->ms(), "001001000000002");</span><br><span>                ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000002");</span><br><span>          OSMO_ASSERT(ms1 != NULL);</span><br><span>            OSMO_ASSERT(ms1 != ms2);</span><br><span style="color: hsl(0, 100%, 40%);">-                OSMO_ASSERT(strcmp(ms1->imsi(), "001001000000002") == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-          OSMO_ASSERT(strcmp(ms2->imsi(), "") == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_ASSERT(strcmp(ms_imsi(ms1), "001001000000002") == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(strcmp(ms_imsi(ms2), "") == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         ms_unref(ms2);</span><br><span>       }</span><br><span> </span><br><span>        ms2 = the_bts.ms_store().get_ms(0xf1000001);</span><br><span>@@ -539,8 +542,8 @@</span><br><span> </span><br><span>       ms = the_bts.ms_store().get_ms(0, 0, imsi);</span><br><span>  OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->dl_tbf() != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   ms->dl_tbf()->set_ta(0);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ms_dl_tbf(ms) != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   ms_dl_tbf(ms)->set_ta(0);</span><br><span> </span><br><span>     /* Handle LLC frame 2 */</span><br><span>     memset(buf, 2, sizeof(buf));</span><br><span>@@ -549,7 +552,7 @@</span><br><span>   OSMO_ASSERT(rc >= 0);</span><br><span> </span><br><span>         /* TBF establishment fails (timeout) */</span><br><span style="color: hsl(0, 100%, 40%);">- tbf_free(ms->dl_tbf());</span><br><span style="color: hsl(120, 100%, 40%);">+    tbf_free(ms_dl_tbf(ms));</span><br><span> </span><br><span>         /* Handle LLC frame 3 */</span><br><span>     memset(buf, 3, sizeof(buf));</span><br><span>@@ -557,7 +560,7 @@</span><br><span>           delay_csec, buf, sizeof(buf));</span><br><span>       OSMO_ASSERT(rc >= 0);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ms->dl_tbf() != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_dl_tbf(ms) != NULL);</span><br><span> </span><br><span>      /* Get first BSN */</span><br><span>  struct msgb *msg;</span><br><span>@@ -572,8 +575,8 @@</span><br><span>                0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 },</span><br><span>  };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  while (ms->dl_tbf()->have_data()) {</span><br><span style="color: hsl(0, 100%, 40%);">-               msg = ms->dl_tbf()->create_dl_acked_block(fn += 4, 7);</span><br><span style="color: hsl(120, 100%, 40%);">+  while (ms_dl_tbf(ms)->have_data()) {</span><br><span style="color: hsl(120, 100%, 40%);">+               msg = ms_dl_tbf(ms)->create_dl_acked_block(fn += 4, 7);</span><br><span>           fprintf(stderr, "MSG = %s\n", msgb_hexdump(msg));</span><br><span>          if (!msgb_eq_data_print(msg, exp[expected_data - 1], GSM_MACBLOCK_LEN))</span><br><span>                      fprintf(stderr, "%s failed at %u\n", __func__, expected_data);</span><br><span>@@ -742,8 +745,8 @@</span><br><span> </span><br><span>   ms = the_bts->ms_by_tlli(tlli);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->ta() == qta/4);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_ta(ms) == qta/4);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span> </span><br><span>    /*</span><br><span>    * TS 44.060, B.8.1</span><br><span>@@ -890,8 +893,8 @@</span><br><span> </span><br><span>        ms = the_bts->ms_by_tlli(tlli);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->ta() == qta/4);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_ta(ms) == qta/4);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span> </span><br><span>    /*</span><br><span>    * TS 44.060, B.8.1</span><br><span>@@ -1386,8 +1389,8 @@</span><br><span> </span><br><span>      ms = the_bts->ms_by_tlli(tlli);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->ta() == qta/4);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_ta(ms) == qta/4);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span> </span><br><span>    return ul_tbf;</span><br><span> }</span><br><span>@@ -1469,8 +1472,8 @@</span><br><span> </span><br><span>      ms = the_bts->ms_by_tlli(tlli);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->ta() == qta/4);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_ta(ms) == qta/4);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span> </span><br><span>    return ul_tbf;</span><br><span> }</span><br><span>@@ -1554,8 +1557,8 @@</span><br><span> </span><br><span>      ms = the_bts->ms_by_tlli(tlli);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->ta() == qta/4);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_ta(ms) == qta/4);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span> </span><br><span>    return ul_tbf;</span><br><span> }</span><br><span>@@ -1637,8 +1640,8 @@</span><br><span> </span><br><span>      ms = the_bts->ms_by_tlli(tlli);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->ta() == qta/4);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_ta(ms) == qta/4);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span> </span><br><span>    return ul_tbf;</span><br><span> }</span><br><span>@@ -1655,7 +1658,7 @@</span><br><span> </span><br><span>      ms = the_bts->ms_by_imsi(imsi);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->dl_tbf() != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_dl_tbf(ms) != NULL);</span><br><span> </span><br><span>      if (imsi[0] && strcmp(imsi, "000") != 0) {</span><br><span>                 ms2 = the_bts->ms_by_tlli(tlli);</span><br><span>@@ -1672,7 +1675,7 @@</span><br><span> </span><br><span>      ms = the_bts->ms_by_tlli(tlli);</span><br><span>   OSMO_ASSERT(ms);</span><br><span style="color: hsl(0, 100%, 40%);">-        dl_tbf = ms->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+     dl_tbf = ms_dl_tbf(ms);</span><br><span>      OSMO_ASSERT(dl_tbf);</span><br><span> </span><br><span>     while (dl_tbf->have_data()) {</span><br><span>@@ -1692,7 +1695,7 @@</span><br><span> {</span><br><span>        fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());</span><br><span>  if (print_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-           fprintf(stderr, "Got MS: TLLI = 0x%08x, TA = %d\n", ul_tbf->ms()->tlli(), ul_tbf->ms()->ta());</span><br><span style="color: hsl(120, 100%, 40%);">+          fprintf(stderr, "Got MS: TLLI = 0x%08x, TA = %d\n", ms_tlli(ul_tbf->ms()), ms_ta(ul_tbf->ms()));</span><br><span> }</span><br><span> </span><br><span> static void test_tbf_single_phase()</span><br><span>@@ -1866,10 +1869,10 @@</span><br><span>   fprintf(stderr, "=== end %s ===\n", __func__);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static inline void print_ms(const GprsMs *ms, bool old)</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void print_ms(GprsMs *ms, bool old)</span><br><span> {</span><br><span>     fprintf(stderr, "%s MS: TLLI = 0x%08x, TA = %d, IMSI = %s, LLC = %zu\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              old ? "Old" : "New", ms->tlli(), ms->ta(), ms->imsi(), ms->llc_queue()->size());</span><br><span style="color: hsl(120, 100%, 40%);">+           old ? "Old" : "New", ms_tlli(ms), ms_ta(ms), ms_imsi(ms), llc_queue_size(ms_llc_queue(ms)));</span><br><span> }</span><br><span> </span><br><span> static void test_tbf_ra_update_rach()</span><br><span>@@ -1905,9 +1908,9 @@</span><br><span>   send_control_ack(ul_tbf);</span><br><span> </span><br><span>        /* Make sure the RAU Accept gets sent to the MS */</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms1->llc_queue()->size() == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 1);</span><br><span>         transmit_dl_data(&the_bts, tlli1, &fn);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms1->llc_queue()->size() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 0);</span><br><span> </span><br><span>     /* Now establish a new TBF for the RA UPDATE COMPLETE (new TLLI) */</span><br><span>  ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli2, &fn, qta,</span><br><span>@@ -1963,8 +1966,8 @@</span><br><span>        send_dl_data(&the_bts, tlli1, imsi, (const uint8_t *)"DATA 2 *************", 20);</span><br><span>      print_ms(ms1, true);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms1->llc_queue()->size() == 2);</span><br><span style="color: hsl(0, 100%, 40%);">-       dl_tbf = ms1->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+  dl_tbf = ms_dl_tbf(ms1);</span><br><span>     OSMO_ASSERT(dl_tbf != NULL);</span><br><span> </span><br><span>     /* Get rid of old UL TBF */</span><br><span>@@ -1986,10 +1989,10 @@</span><br><span>        OSMO_ASSERT(ms2 == ms);</span><br><span> </span><br><span>  /* A DL TBF should still exist */</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms->dl_tbf());</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ms_dl_tbf(ms));</span><br><span> </span><br><span>      /* No queued packets should be lost */</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms->llc_queue()->size() == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms)) == 2);</span><br><span> </span><br><span>      fprintf(stderr, "=== end %s ===\n", __func__);</span><br><span> }</span><br><span>@@ -2022,8 +2025,8 @@</span><br><span>        send_dl_data(&the_bts, tlli1, imsi, (const uint8_t *)"DATA 2 *************", 20);</span><br><span>      print_ms(ms1, true);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms1->llc_queue()->size() == 2);</span><br><span style="color: hsl(0, 100%, 40%);">-       dl_tbf = ms1->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+  dl_tbf = ms_dl_tbf(ms1);</span><br><span>     OSMO_ASSERT(dl_tbf != NULL);</span><br><span> </span><br><span>     /* Get rid of old UL TBF */</span><br><span>@@ -2045,10 +2048,10 @@</span><br><span>        OSMO_ASSERT(ms1 != ms);</span><br><span> </span><br><span>  /* DL TBF should be removed */</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(!ms->dl_tbf());</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(!ms_dl_tbf(ms));</span><br><span> </span><br><span>     /* No queued packets should be lost */</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms->llc_queue()->size() == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms)) == 2);</span><br><span> </span><br><span>      fprintf(stderr, "=== end %s ===\n", __func__);</span><br><span> }</span><br><span>@@ -2099,11 +2102,11 @@</span><br><span> </span><br><span>  /* Transmit all data */</span><br><span>      transmit_dl_data(&the_bts, tlli1, &fn);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms1->llc_queue()->size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms1->dl_tbf());</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms1->dl_tbf()->state_is(GPRS_RLCMAC_FINISHED));</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms1)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_dl_tbf(ms1));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_dl_tbf(ms1)->state_is(GPRS_RLCMAC_FINISHED));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     dl_tbf1 = ms1->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+   dl_tbf1 = ms_dl_tbf(ms1);</span><br><span> </span><br><span>        /* Send some LLC frames */</span><br><span>   for (i = 0; i < 10; i++) {</span><br><span>@@ -2132,10 +2135,10 @@</span><br><span> </span><br><span>  ms2 = the_bts.ms_by_tlli(tlli1);</span><br><span>     OSMO_ASSERT(ms2 == ms1);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms2->dl_tbf());</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms2->dl_tbf()->state_is(GPRS_RLCMAC_ASSIGN));</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_dl_tbf(ms2));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_dl_tbf(ms2)->state_is(GPRS_RLCMAC_ASSIGN));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       dl_tbf2 = ms2->dl_tbf();</span><br><span style="color: hsl(120, 100%, 40%);">+   dl_tbf2 = ms_dl_tbf(ms2);</span><br><span> </span><br><span>        OSMO_ASSERT(dl_tbf1 != dl_tbf2);</span><br><span> </span><br><span>@@ -2144,9 +2147,9 @@</span><br><span> </span><br><span>     /* Transmit all data */</span><br><span>      transmit_dl_data(&the_bts, tlli1, &fn);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(ms2->llc_queue()->size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(ms2->dl_tbf());</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(ms2->dl_tbf()->state_is(GPRS_RLCMAC_FINISHED));</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(llc_queue_size(ms_llc_queue(ms2)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_dl_tbf(ms2));</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(ms_dl_tbf(ms2)->state_is(GPRS_RLCMAC_FINISHED));</span><br><span> </span><br><span>  fprintf(stderr, "=== end %s ===\n", __func__);</span><br><span> }</span><br><span>@@ -2411,8 +2414,8 @@</span><br><span> </span><br><span>    ms = the_bts->ms_by_tlli(tlli);</span><br><span>   OSMO_ASSERT(ms != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ms->ta() == qta/4);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(ms->ul_tbf() == ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ms_ta(ms) == qta/4);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ms_ul_tbf(ms) == ul_tbf);</span><br><span> </span><br><span>    egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg;</span><br><span>     egprs3->si = 0;</span><br><span>@@ -2799,9 +2802,7 @@</span><br><span> </span><br><span>       OSMO_ASSERT(bsn1 == 0);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     dl_tbf->ms()->set_current_cs_dl</span><br><span style="color: hsl(0, 100%, 40%);">-           (static_cast < enum CodingScheme ></span><br><span style="color: hsl(0, 100%, 40%);">-                        (CS4 + demanded_mcs));</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + demanded_mcs));</span><br><span> </span><br><span>     fn = fn_add_blocks(fn, 1);</span><br><span> </span><br><span>@@ -2831,9 +2832,7 @@</span><br><span>       OSMO_ASSERT(egprs3->cps == 3);</span><br><span> </span><br><span>        /* Handle (MCS3, MCS3) -> MCS6 case */</span><br><span style="color: hsl(0, 100%, 40%);">-       dl_tbf->ms()->set_current_cs_dl</span><br><span style="color: hsl(0, 100%, 40%);">-           (static_cast < enum CodingScheme ></span><br><span style="color: hsl(0, 100%, 40%);">-                        (CS4 + mcs));</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + mcs));</span><br><span> </span><br><span>      NACK(dl_tbf, 0);</span><br><span> </span><br><span>@@ -2880,9 +2879,7 @@</span><br><span> </span><br><span>     NACK(dl_tbf, 0);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    dl_tbf->ms()->set_current_cs_dl</span><br><span style="color: hsl(0, 100%, 40%);">-           (static_cast < enum CodingScheme ></span><br><span style="color: hsl(0, 100%, 40%);">-                        (CS4 + demanded_mcs));</span><br><span style="color: hsl(120, 100%, 40%);">+        ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + demanded_mcs));</span><br><span> </span><br><span>     fn = fn_add_blocks(fn, 1);</span><br><span> </span><br><span>@@ -2967,9 +2964,7 @@</span><br><span>               NACK(dl_tbf, 1);</span><br><span> </span><br><span>                 /* Set the demanded MCS to demanded_mcs */</span><br><span style="color: hsl(0, 100%, 40%);">-              dl_tbf->ms()->set_current_cs_dl</span><br><span style="color: hsl(0, 100%, 40%);">-                   (static_cast < enum CodingScheme ></span><br><span style="color: hsl(0, 100%, 40%);">-                                (CS4 + demanded_mcs));</span><br><span style="color: hsl(120, 100%, 40%);">+                ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + demanded_mcs));</span><br><span> </span><br><span>             fn = fn_add_blocks(fn, 1);</span><br><span>           /* Retransmit the first RLC data block with demanded_mcs */</span><br><span>@@ -2994,9 +2989,7 @@</span><br><span>          NACK(dl_tbf, 0);</span><br><span>             NACK(dl_tbf, 1);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            dl_tbf->ms()->set_current_cs_dl</span><br><span style="color: hsl(0, 100%, 40%);">-                   (static_cast < enum CodingScheme ></span><br><span style="color: hsl(0, 100%, 40%);">-                                (CS4 + demanded_mcs));</span><br><span style="color: hsl(120, 100%, 40%);">+                ms_set_current_cs_dl(dl_tbf->ms(), static_cast < enum CodingScheme > (CS4 + demanded_mcs));</span><br><span> </span><br><span>             fn = fn_add_blocks(fn, 1);</span><br><span>           /* Send first, second RLC data blocks with demanded_mcs */</span><br><span>@@ -3264,8 +3257,8 @@</span><br><span>   pcu_vty_init();</span><br><span> </span><br><span>  /* Initialize shared UL measurements */</span><br><span style="color: hsl(0, 100%, 40%);">- meas.set_link_qual(12);</span><br><span style="color: hsl(0, 100%, 40%);">- meas.set_rssi(31);</span><br><span style="color: hsl(120, 100%, 40%);">+    pcu_l1_meas_set_link_qual(&meas, 12);</span><br><span style="color: hsl(120, 100%, 40%);">+     pcu_l1_meas_set_rssi(&meas, 31);</span><br><span> </span><br><span>     test_tbf_base();</span><br><span>     test_tbf_tlli_update();</span><br><span>diff --git a/tests/types/TypesTest.cpp b/tests/types/TypesTest.cpp</span><br><span>index f224146..bc24b30 100644</span><br><span>--- a/tests/types/TypesTest.cpp</span><br><span>+++ b/tests/types/TypesTest.cpp</span><br><span>@@ -58,27 +58,27 @@</span><br><span>               gprs_llc llc;</span><br><span>                llc.init();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-         OSMO_ASSERT(llc.chunk_size() == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-             OSMO_ASSERT(llc.remaining_space() == LLC_MAX_LEN);</span><br><span style="color: hsl(0, 100%, 40%);">-              OSMO_ASSERT(llc.frame_length() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(llc_chunk_size(&llc) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(llc_remaining_space(&llc) == LLC_MAX_LEN);</span><br><span style="color: hsl(120, 100%, 40%);">+            OSMO_ASSERT(llc_frame_length(&llc) == 0);</span><br><span> </span><br><span>            llc.put_frame(data, 2);</span><br><span style="color: hsl(0, 100%, 40%);">-         OSMO_ASSERT(llc.remaining_space() == LLC_MAX_LEN - 2);</span><br><span style="color: hsl(0, 100%, 40%);">-          OSMO_ASSERT(llc.frame_length() == 2);</span><br><span style="color: hsl(0, 100%, 40%);">-           OSMO_ASSERT(llc.chunk_size() == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(llc_remaining_space(&llc) == LLC_MAX_LEN - 2);</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(llc_frame_length(&llc) == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(llc_chunk_size(&llc) == 2);</span><br><span>          OSMO_ASSERT(llc.frame[0] == 1);</span><br><span>              OSMO_ASSERT(llc.frame[1] == 2);</span><br><span> </span><br><span>          llc.append_frame(&data[3], 1);</span><br><span style="color: hsl(0, 100%, 40%);">-              OSMO_ASSERT(llc.remaining_space() == LLC_MAX_LEN - 3);</span><br><span style="color: hsl(0, 100%, 40%);">-          OSMO_ASSERT(llc.frame_length() == 3);</span><br><span style="color: hsl(0, 100%, 40%);">-           OSMO_ASSERT(llc.chunk_size() == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(llc_remaining_space(&llc) == LLC_MAX_LEN - 3);</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(llc_frame_length(&llc) == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(llc_chunk_size(&llc) == 3);</span><br><span> </span><br><span>              /* consume two bytes */</span><br><span style="color: hsl(0, 100%, 40%);">-         llc.consume(&out, 1);</span><br><span style="color: hsl(0, 100%, 40%);">-               OSMO_ASSERT(llc.remaining_space() == LLC_MAX_LEN - 3);</span><br><span style="color: hsl(0, 100%, 40%);">-          OSMO_ASSERT(llc.frame_length() == 3);</span><br><span style="color: hsl(0, 100%, 40%);">-           OSMO_ASSERT(llc.chunk_size() == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+           llc_consume_data(&llc, &out, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(llc_remaining_space(&llc) == LLC_MAX_LEN - 3);</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(llc_frame_length(&llc) == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(llc_chunk_size(&llc) == 2);</span><br><span> </span><br><span>              /* check that the bytes are as we expected */</span><br><span>                OSMO_ASSERT(llc.frame[0] == 1);</span><br><span>@@ -86,9 +86,9 @@</span><br><span>          OSMO_ASSERT(llc.frame[2] == 4);</span><br><span> </span><br><span>          /* now fill the frame */</span><br><span style="color: hsl(0, 100%, 40%);">-                llc.append_frame(data, llc.remaining_space() - 1);</span><br><span style="color: hsl(0, 100%, 40%);">-              OSMO_ASSERT(llc.fits_in_current_frame(1));</span><br><span style="color: hsl(0, 100%, 40%);">-              OSMO_ASSERT(!llc.fits_in_current_frame(2));</span><br><span style="color: hsl(120, 100%, 40%);">+           llc.append_frame(data, llc_remaining_space(&llc) - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+            OSMO_ASSERT(llc_fits_in_current_frame(&llc, 1));</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(!llc_fits_in_current_frame(&llc, 2));</span><br><span>        }</span><br><span> }</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-pcu/+/21748">change 21748</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-pcu/+/21748"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-pcu </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c </div>
<div style="display:none"> Gerrit-Change-Number: 21748 </div>
<div style="display:none"> Gerrit-PatchSet: 7 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>