<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-pcu/+/23291">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP: Add new PDCH UL Controller, drop SBAllocator class<br><br>Right now we handle different types of UL allocations in different<br>classes like PollAllocator and SBAllocator, and they usually don't take<br>into account the other one in most cases. Furthermore, those objects are<br>usually per-BTS object, instead of per PDCH object.<br><br>This is a first step towards having a unified per-PDCH controller which<br>takes care of controlling what is scheduled and hence expected on the<br>uplink. Each PDCH has a UL Controller which keeps track of all reserved<br>uplink frame, be it SB, RRBP poll or USF assigned, all under the same<br>API.<br><br>As a first step, only the SBA part is fully implemented and used (being<br>it the easiest part to replace); TBF poll+usf will come in follow-up<br>patches later on. As a result, the SBAllocator per-BTS class dissappears<br>but some of its code is refactored/reused to provide more features to the<br>gprs_rlcmac_sba object, which is also further integrated into the new UL<br>Controller.<br><br>Related: OS#5020<br>Change-Id: I84b24beea4a1aa2c1528f41435f77bd16df2b947<br>---<br>M src/Makefile.am<br>M src/bts.cpp<br>M src/bts.h<br>M src/gprs_rlcmac_sched.cpp<br>M src/pcu_l1_if.cpp<br>M src/pdch.cpp<br>M src/pdch.h<br>A src/pdch_ul_controller.c<br>A src/pdch_ul_controller.h<br>M src/poll_controller.cpp<br>A src/sba.c<br>D src/sba.cpp<br>M src/sba.h<br>M src/tbf.cpp<br>M tests/tbf/TbfTest.cpp<br>M tests/tbf/TbfTest.err<br>16 files changed, 463 insertions(+), 224 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/91/23291/1</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 eefbea1..ab9aeeb 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -62,9 +62,10 @@</span><br><span>     tbf_dl.cpp \</span><br><span>         bts.cpp \</span><br><span>    pdch.cpp \</span><br><span style="color: hsl(120, 100%, 40%);">+    pdch_ul_controller.c \</span><br><span>       poll_controller.cpp \</span><br><span>        encoding.cpp \</span><br><span style="color: hsl(0, 100%, 40%);">-  sba.cpp \</span><br><span style="color: hsl(120, 100%, 40%);">+     sba.c \</span><br><span>      decoding.cpp \</span><br><span>       llc.cpp \</span><br><span>    rlc.cpp \</span><br><span>@@ -100,6 +101,7 @@</span><br><span>      tbf_dl.h \</span><br><span>   bts.h \</span><br><span>      pdch.h \</span><br><span style="color: hsl(120, 100%, 40%);">+      pdch_ul_controller.h \</span><br><span>       poll_controller.h \</span><br><span>  encoding.h \</span><br><span>         sba.h \</span><br><span>diff --git a/src/bts.cpp b/src/bts.cpp</span><br><span>index 1d3f690..a7d475c 100644</span><br><span>--- a/src/bts.cpp</span><br><span>+++ b/src/bts.cpp</span><br><span>@@ -212,7 +212,6 @@</span><br><span>        * m_ms_store's destructor */</span><br><span>    bts->ms_store->cleanup();</span><br><span>      delete bts->ms_store;</span><br><span style="color: hsl(0, 100%, 40%);">-        delete bts->sba;</span><br><span>  delete bts->pollController;</span><br><span> </span><br><span>   if (bts->ratectrs) {</span><br><span>@@ -246,7 +245,6 @@</span><br><span>        bts->nr = bts_nr;</span><br><span> </span><br><span>     bts->pollController = new PollController(*bts);</span><br><span style="color: hsl(0, 100%, 40%);">-      bts->sba = new SBAController(*bts);</span><br><span>       bts->ms_store = new GprsMsStorage(bts);</span><br><span> </span><br><span>       bts->cur_fn = 0;</span><br><span>@@ -819,10 +817,43 @@</span><br><span>  return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_sba *bts_alloc_sba(struct gprs_rlcmac_bts *bts, uint8_t ta)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_pdch *pdch;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_rlcmac_sba *sba = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   int8_t trx, ts;</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%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (trx = 0; trx < 8; trx++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            for (ts = 7; ts >= 0; ts--) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      pdch = &bts->trx[trx].pdch[ts];</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (!pdch->is_enabled())</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue;</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%);">+             if (ts >= 0)</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%);">+     if (trx == 8) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return 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%);">+   sba = sba_alloc(bts, pdch, ta);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!sba)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        bts_do_rate_ctr_inc(bts, CTR_SBA_ALLOCATED);</span><br><span style="color: hsl(120, 100%, 40%);">+  return sba;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int bts_rcv_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip)</span><br><span> {</span><br><span>    struct chan_req_params chan_req = { 0 };</span><br><span>     struct gprs_rlcmac_ul_tbf *tbf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_rlcmac_sba *sba;</span><br><span>         uint8_t trx_no, ts_no;</span><br><span>       uint32_t sb_fn = 0;</span><br><span>  uint8_t usf = 7;</span><br><span>@@ -864,14 +895,18 @@</span><br><span> </span><br><span>         /* Should we allocate a single block or an Uplink TBF? */</span><br><span>    if (chan_req.single_block) {</span><br><span style="color: hsl(0, 100%, 40%);">-            rc = bts_sba(bts)->alloc(&trx_no, &ts_no, &sb_fn, ta);</span><br><span style="color: hsl(0, 100%, 40%);">-           if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              sba = bts_alloc_sba(bts, ta);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!sba) {</span><br><span>                  LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource for "</span><br><span style="color: hsl(0, 100%, 40%);">-                         "single block allocation: rc=%d\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+                            "single block allocation\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                  rc = -EBUSY;</span><br><span>                         /* Send RR Immediate Assignment Reject */</span><br><span>                    goto send_imm_ass_rej;</span><br><span>               }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         trx_no = sba->pdch->trx_no();</span><br><span style="color: hsl(120, 100%, 40%);">+           ts_no = sba->pdch->ts_no;</span><br><span style="color: hsl(120, 100%, 40%);">+               sb_fn = sba->fn;</span><br><span>          tsc = bts->trx[trx_no].pdch[ts_no].tsc;</span><br><span>           LOGP(DRLCMAC, LOGL_DEBUG, "Allocated a single block at "</span><br><span>                "SBFn=%u TRX=%u TS=%u\n", sb_fn, trx_no, ts_no);</span><br><span>@@ -1076,11 +1111,6 @@</span><br><span>     return ms;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct SBAController *bts_sba(struct gprs_rlcmac_bts *bts)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  return bts->sba;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct GprsMsStorage *bts_ms_store(struct gprs_rlcmac_bts *bts)</span><br><span> {</span><br><span>         return bts->ms_store;</span><br><span>diff --git a/src/bts.h b/src/bts.h</span><br><span>index 3ddf501..051a698 100644</span><br><span>--- a/src/bts.h</span><br><span>+++ b/src/bts.h</span><br><span>@@ -253,7 +253,6 @@</span><br><span>      uint8_t max_cs_dl, max_cs_ul;</span><br><span>        uint8_t max_mcs_dl, max_mcs_ul;</span><br><span>      struct PollController *pollController;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct SBAController *sba;</span><br><span>   struct rate_ctr_group *ratectrs;</span><br><span>     struct osmo_stat_item_group *statg;</span><br><span> </span><br><span>@@ -308,8 +307,6 @@</span><br><span>                          enum pcu_gsmtap_category categ, uint8_t channel,</span><br><span>                     const struct rach_ind_params *rip);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct SBAController *bts_sba(struct gprs_rlcmac_bts *bts);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct GprsMsStorage *bts_ms_store(struct gprs_rlcmac_bts *bts);</span><br><span> </span><br><span> struct GprsMs *bts_ms_by_tlli(struct gprs_rlcmac_bts *bts, uint32_t tlli, uint32_t old_tlli);</span><br><span>@@ -339,6 +336,8 @@</span><br><span> </span><br><span> struct gprs_rlcmac_bts *bts_alloc(struct gprs_pcu *pcu, uint8_t bts_nr);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_sba *bts_alloc_sba(struct gprs_rlcmac_bts *bts, uint8_t ta);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void bts_recalc_initial_cs(struct gprs_rlcmac_bts *bts);</span><br><span> void bts_recalc_initial_mcs(struct gprs_rlcmac_bts *bts);</span><br><span> void bts_recalc_max_cs(struct gprs_rlcmac_bts *bts);</span><br><span>diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp</span><br><span>index 51deb65..d95cd81 100644</span><br><span>--- a/src/gprs_rlcmac_sched.cpp</span><br><span>+++ b/src/gprs_rlcmac_sched.cpp</span><br><span>@@ -482,11 +482,10 @@</span><br><span>                         block_nr, poll_fn, tbf_name(tbf_cand.poll));</span><br><span>                 usf = USF_UNUSED;</span><br><span>    /* else. check for sba */</span><br><span style="color: hsl(0, 100%, 40%);">-       } else if ((sba_fn = bts_sba(bts)->sched(trx, ts, fn, block_nr)) != 0xffffffff) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "</span><br><span style="color: hsl(0, 100%, 40%);">-                       "TS=%d FN=%d block_nr=%d scheduling free USF for "</span><br><span style="color: hsl(0, 100%, 40%);">-                    "single block allocation at FN=%d\n", trx, ts, fn,</span><br><span style="color: hsl(0, 100%, 40%);">-                    block_nr, sba_fn);</span><br><span style="color: hsl(120, 100%, 40%);">+} else if ((sba_fn = find_sba_rts(pdch, fn, block_nr)) != 0xffffffff) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: "</span><br><span style="color: hsl(120, 100%, 40%);">+                   "FN=%d block_nr=%d scheduling free USF for "</span><br><span style="color: hsl(120, 100%, 40%);">+                        "single block allocation at FN=%d\n", fn, block_nr, sba_fn);</span><br><span>               usf = USF_UNUSED;</span><br><span>    /* else, we search for uplink resource */</span><br><span>    } else {</span><br><span>diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp</span><br><span>index 1f87666..412a220 100644</span><br><span>--- a/src/pcu_l1_if.cpp</span><br><span>+++ b/src/pcu_l1_if.cpp</span><br><span>@@ -285,7 +285,11 @@</span><br><span> int pcu_rx_data_ind_pdtch(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_pdch *pdch, uint8_t *data,</span><br><span>     uint8_t len, uint32_t fn, struct pcu_l1_meas *meas)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        return pdch->rcv_block(data, len, fn, meas);</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = pdch->rcv_block(data, len, fn, meas);</span><br><span style="color: hsl(120, 100%, 40%);">+ pdch_ulc_expire_fn(pdch->ulc, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span> }</span><br><span> </span><br><span> static int pcu_rx_data_ind_bcch(struct gprs_rlcmac_bts *bts, uint8_t *data, uint8_t len)</span><br><span>diff --git a/src/pdch.cpp b/src/pdch.cpp</span><br><span>index 466eaa5..2d66ac1 100644</span><br><span>--- a/src/pdch.cpp</span><br><span>+++ b/src/pdch.cpp</span><br><span>@@ -139,6 +139,7 @@</span><br><span>   /*  Initialize the PTCCH/D message (Packet Timing Advance Control Channel) */</span><br><span>        memset(pdch->ptcch_msg, PTCCH_TAI_FREE, PTCCH_TAI_NUM);</span><br><span>   memset(pdch->ptcch_msg + PTCCH_TAI_NUM, PTCCH_PADDING, 7);</span><br><span style="color: hsl(120, 100%, 40%);">+ pdch->ulc = pdch_ulc_alloc(pdch, trx->bts);</span><br><span> }</span><br><span> </span><br><span> void gprs_rlcmac_pdch::enable()</span><br><span>@@ -169,7 +170,7 @@</span><br><span>  while ((pag = dequeue_paging()))</span><br><span>             talloc_free(pag);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   bts_sba(trx->bts)->free_resources(this);</span><br><span style="color: hsl(120, 100%, 40%);">+        talloc_free(this->ulc);</span><br><span> }</span><br><span> </span><br><span> struct gprs_rlcmac_paging *gprs_rlcmac_pdch::dequeue_paging()</span><br><span>@@ -604,10 +605,10 @@</span><br><span>                 LOGPDCH(this, 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 style="color: hsl(0, 100%, 40%);">-               sba = bts_sba(bts())->find(this, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+              sba = pdch_ulc_get_sba(this->ulc, fn);</span><br><span>            if (sba) {</span><br><span>                   ms_set_ta(ms, sba->ta);</span><br><span style="color: hsl(0, 100%, 40%);">-                      bts_sba(bts())->free_sba(sba);</span><br><span style="color: hsl(120, 100%, 40%);">+                     sba_free(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>                                 "MS requests UL TBF in PACKET RESOURCE REQ of "</span><br><span>@@ -702,9 +703,9 @@</span><br><span>            ms = bts_alloc_ms(bts(), 0, 0);</span><br><span>              ms_set_tlli(ms, report->TLLI);</span><br><span>    }</span><br><span style="color: hsl(0, 100%, 40%);">-       if ((sba = bts_sba(bts())->find(this, fn))) {</span><br><span style="color: hsl(120, 100%, 40%);">+      if ((sba = pdch_ulc_get_sba(this->ulc, fn))) {</span><br><span>            ms_set_ta(ms, sba->ta);</span><br><span style="color: hsl(0, 100%, 40%);">-              bts_sba(bts())->free_sba(sba);</span><br><span style="color: hsl(120, 100%, 40%);">+             sba_free(sba);</span><br><span>       }</span><br><span>    gprs_rlcmac_meas_rep(ms, report);</span><br><span> }</span><br><span>diff --git a/src/pdch.h b/src/pdch.h</span><br><span>index fb28019..cfa0195 100644</span><br><span>--- a/src/pdch.h</span><br><span>+++ b/src/pdch.h</span><br><span>@@ -28,6 +28,7 @@</span><br><span> #include <osmocom/core/linuxlist.h></span><br><span> #include "gsm_rlcmac.h"</span><br><span> #include "coding_scheme.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "pdch_ul_controller.h"</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span>@@ -126,6 +127,7 @@</span><br><span>        /* back pointers */</span><br><span>  struct gprs_rlcmac_trx *trx;</span><br><span>         uint8_t ts_no;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct pdch_ulc *ulc;</span><br><span> </span><br><span> #ifdef __cplusplus</span><br><span> private:</span><br><span>@@ -191,10 +193,9 @@</span><br><span> void pdch_disable(struct gprs_rlcmac_pdch *pdch);</span><br><span> #ifdef __cplusplus</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span> #define LOGPDCH(pdch, category, level, fmt, args...) \</span><br><span>     LOGP(category, level, "PDCH(bts=%" PRIu8 ",trx=%" PRIu8 ",ts=%" PRIu8 ") " fmt, \</span><br><span>         (pdch)->trx->bts->nr, (pdch)->trx->trx_no, (pdch)->ts_no, \</span><br><span>        ## args)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span>diff --git a/src/pdch_ul_controller.c b/src/pdch_ul_controller.c</span><br><span>new file mode 100644</span><br><span>index 0000000..7864476</span><br><span>--- /dev/null</span><br><span>+++ b/src/pdch_ul_controller.c</span><br><span>@@ -0,0 +1,223 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* pdch_ul_controller.c</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@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%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "pdch_ul_controller.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "bts.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "sba.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "pdch.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* TS 44.060 Table 10.4.5.1 states maximum RRBP is N + 26. Give extra space for time diff between Tx and Rx? */</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAX_FN_RESERVED (27 + 50)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string pdch_ul_node_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   { PDCH_ULC_NODE_TBF_USF, "USF" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { PDCH_ULC_NODE_TBF_POLL, "POLL" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { PDCH_ULC_NODE_SBA, "SBA" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { 0, 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%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void _free_pdch_ulc_node(struct pdch_ulc_node *item)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (item->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case PDCH_ULC_NODE_TBF_USF:</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case PDCH_ULC_NODE_TBF_POLL:</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case PDCH_ULC_NODE_SBA:</span><br><span style="color: hsl(120, 100%, 40%);">+               sba_free(sba);  //it will detach it from pdch_ulc</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 int ulc_talloc_destructor(struct pdch_ulc* ulc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   /* TODO: iterate over rb-tree and free whatever */</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%);">+struct pdch_ulc *pdch_ulc_alloc(struct gprs_rlcmac_pdch *pdch, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct pdch_ulc* ulc;</span><br><span style="color: hsl(120, 100%, 40%);">+ ulc = talloc_zero(ctx, struct pdch_ulc);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!ulc)</span><br><span style="color: hsl(120, 100%, 40%);">+             return ulc;</span><br><span style="color: hsl(120, 100%, 40%);">+   talloc_set_destructor(ulc, ulc_talloc_destructor);</span><br><span style="color: hsl(120, 100%, 40%);">+    ulc->pdch = pdch;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ulc->pool_ctx = talloc_pool(ulc, sizeof(struct pdch_ulc_node) * MAX_FN_RESERVED);</span><br><span style="color: hsl(120, 100%, 40%);">+  return ulc;</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 pdch_ulc_node *pdch_ulc_get_node(struct pdch_ulc *ulc, uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct rb_node *node;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct pdch_ulc_node *this;</span><br><span style="color: hsl(120, 100%, 40%);">+   for (node = rb_first(&ulc->tree_root); node; node = rb_next(node)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           this = container_of(node, struct pdch_ulc_node, node);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (this->fn == fn)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return this;</span><br><span style="color: hsl(120, 100%, 40%);">+          if (this->fn > fn)</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%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+struct pdch_ulc_node *pdch_ulc_pop_node(struct pdch_ulc *ulc, uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct pdch_ulc_node *item = pdch_ulc_get_node(ulc, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!item)</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  rb_erase(&item->node, &ulc->tree_root);</span><br><span style="color: hsl(120, 100%, 40%);">+ return item;</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_sba *pdch_ulc_get_sba(struct pdch_ulc *ulc, uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct pdch_ulc_node *item = pdch_ulc_get_node(ulc, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!item || item->type != PDCH_ULC_NODE_SBA) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /*LOGPDCH(ulc->pdch, DRLCMAC, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                  "Expected SBA at FN=%u but got type %s\n", fn,</span><br><span style="color: hsl(120, 100%, 40%);">+                      item ? get_value_string(pdch_ul_node_names, item->type) :</span><br><span style="color: hsl(120, 100%, 40%);">+                         "EMPTY");*/</span><br><span style="color: hsl(120, 100%, 40%);">+          /* It's OK if we don't find one, this func is used by RTS to see if we need to schedule one */</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     return item->sba.sba;</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_sba *pdch_ulc_pop_sba(struct pdch_ulc *ulc, uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct pdch_ulc_node *item = pdch_ulc_get_node(ulc, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!item || item->type != PDCH_ULC_NODE_SBA) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGPDCH(ulc->pdch, DRLCMAC, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Expected SBA at FN=%" PRIu32 " but got type %s\n", fn,</span><br><span style="color: hsl(120, 100%, 40%);">+                   item ? get_value_string(pdch_ul_node_names, item->type) :</span><br><span style="color: hsl(120, 100%, 40%);">+                         "EMPTY");</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     rb_erase(&item->node, &ulc->tree_root);</span><br><span style="color: hsl(120, 100%, 40%);">+ return item->sba.sba;</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 pdch_ulc_fn_is_free(struct pdch_ulc *ulc, uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return !pdch_ulc_get_node(ulc, fn);</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 pdch_ulc_node *_alloc_node(struct pdch_ulc *ulc, uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct pdch_ulc_node *node;</span><br><span style="color: hsl(120, 100%, 40%);">+   node = talloc_zero(ulc->pool_ctx, struct pdch_ulc_node);</span><br><span style="color: hsl(120, 100%, 40%);">+   node->fn = fn;</span><br><span style="color: hsl(120, 100%, 40%);">+     return node;</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 pdch_ulc_add_node(struct pdch_ulc *ulc, struct pdch_ulc_node *item)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct rb_node **new = &(ulc->tree_root.rb_node);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct rb_node *parent = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      while (*new) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct pdch_ulc_node *this;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         this = container_of(*new, struct pdch_ulc_node, node);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              parent = *new;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (item->fn < this->fn)</span><br><span style="color: hsl(120, 100%, 40%);">+                     new = &((*new)->rb_left);</span><br><span style="color: hsl(120, 100%, 40%);">+              else</span><br><span style="color: hsl(120, 100%, 40%);">+                  new = &((*new)->rb_right);</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%);">+   rb_link_node(&item->node, parent, new);</span><br><span style="color: hsl(120, 100%, 40%);">+        rb_insert_color(&item->node, &ulc->tree_root);</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%);">+int pdch_ulc_reserve_tbf_usf(struct pdch_ulc *ulc, uint32_t fn, struct gprs_rlcmac_ul_tbf *ul_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0; /* TODO: implement */</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 pdch_ulc_reserve_tbf_poll(struct pdch_ulc *ulc, uint32_t fn, struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0; /* TODO: implement */</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 pdch_ulc_reserve_sba(struct pdch_ulc *ulc, struct gprs_rlcmac_sba *sba)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct pdch_ulc_node *item = _alloc_node(ulc, sba->fn);</span><br><span style="color: hsl(120, 100%, 40%);">+    item->type = PDCH_ULC_NODE_SBA;</span><br><span style="color: hsl(120, 100%, 40%);">+    item->sba.sba = sba;</span><br><span style="color: hsl(120, 100%, 40%);">+       return pdch_ulc_add_node(ulc, item);</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 pdch_ulc_release_fn(struct pdch_ulc *ulc, uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct pdch_ulc_node *item = pdch_ulc_get_node(ulc, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!item)</span><br><span style="color: hsl(120, 100%, 40%);">+            return -ENOKEY;</span><br><span style="color: hsl(120, 100%, 40%);">+       rb_erase(&item->node, &ulc->tree_root);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(item);</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%);">+void pdch_ulc_expire_fn(struct pdch_ulc *ulc, uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_sba *sba;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct pdch_ulc_node *item;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Sanity check: */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct rb_node *first = rb_first(&ulc->tree_root);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (first) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct pdch_ulc_node *first_it = container_of(first, struct pdch_ulc_node, node);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (first_it->fn < fn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGPDCH(ulc->pdch, DRLCMAC, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "Expiring FN=%" PRIu32 " but previous FN=%" PRIu32 " is still reserved!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             fn, first_it->fn);</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%);">+   item = pdch_ulc_pop_node(ulc, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!item)</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 (item->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case PDCH_ULC_NODE_TBF_USF:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* TODO: increase N3...*/</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case PDCH_ULC_NODE_TBF_POLL:</span><br><span style="color: hsl(120, 100%, 40%);">+          /* TODO: increase N3...*/</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case PDCH_ULC_NODE_SBA:</span><br><span style="color: hsl(120, 100%, 40%);">+               sba = item->sba.sba;</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGPDCH(sba->pdch, DRLCMAC, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "Timeout for unregistered SBA (FN=%u, TA=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    sba->fn, sba->ta);</span><br><span style="color: hsl(120, 100%, 40%);">+              sba_free(sba);</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%);">+   talloc_free(item);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/pdch_ul_controller.h b/src/pdch_ul_controller.h</span><br><span>new file mode 100644</span><br><span>index 0000000..8382b27</span><br><span>--- /dev/null</span><br><span>+++ b/src/pdch_ul_controller.h</span><br><span>@@ -0,0 +1,80 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* pdch_ul_controller.h</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@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%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxrbtree.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_pdch;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_ul_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_sba;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct pdch_ulc {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_rlcmac_pdch *pdch; /* back pointer */</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t last_fn; /* last FN rx from TDMA clock */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct rb_root tree_root;</span><br><span style="color: hsl(120, 100%, 40%);">+     void *pool_ctx; /* talloc pool of struct pdch_ulc_node  */</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 PdchUlcNode {</span><br><span style="color: hsl(120, 100%, 40%);">+  PDCH_ULC_NODE_TBF_USF,</span><br><span style="color: hsl(120, 100%, 40%);">+        PDCH_ULC_NODE_TBF_POLL,</span><br><span style="color: hsl(120, 100%, 40%);">+       PDCH_ULC_NODE_SBA,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string pdch_ul_node_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct pdch_ulc_node {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct rb_node node;      /*! entry in pdch_ulc->tree_root */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t fn;</span><br><span style="color: hsl(120, 100%, 40%);">+  enum PdchUlcNode type;</span><br><span style="color: hsl(120, 100%, 40%);">+        union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct {</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%);">+            } tbf_usf;</span><br><span style="color: hsl(120, 100%, 40%);">+            struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct gprs_rlcmac_tbf *poll_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+             } tbf_poll;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct gprs_rlcmac_sba *sba;</span><br><span style="color: hsl(120, 100%, 40%);">+          } sba;</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%);">+struct pdch_ulc *pdch_ulc_alloc(struct gprs_rlcmac_pdch *pdch, void *ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int pdch_ulc_reserve_tbf_usf(struct pdch_ulc *ulc, uint32_t fn, struct gprs_rlcmac_ul_tbf *ul_tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+int pdch_ulc_reserve_tbf_poll(struct pdch_ulc *ulc, uint32_t fn, struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+int pdch_ulc_reserve_sba(struct pdch_ulc *ulc, struct gprs_rlcmac_sba *sba);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool pdch_ulc_fn_is_free(struct pdch_ulc *ulc, uint32_t fn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct pdch_ulc_node *pdch_ulc_get_node(struct pdch_ulc *ulc, uint32_t fn);</span><br><span style="color: hsl(120, 100%, 40%);">+struct pdch_ulc_node *pdch_ulc_pop_node(struct pdch_ulc *ulc, uint32_t fn);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_sba *pdch_ulc_get_sba(struct pdch_ulc *ulc, uint32_t fn);</span><br><span style="color: hsl(120, 100%, 40%);">+//struct gprs_rlcmac_sba *pdch_ulc_pop_sba(struct pdch_ulc *ulc, uint32_t fn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int pdch_ulc_release_fn(struct pdch_ulc *ulc, uint32_t fn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void pdch_ulc_expire_fn(struct pdch_ulc *ulc, uint32_t fn);</span><br><span>diff --git a/src/poll_controller.cpp b/src/poll_controller.cpp</span><br><span>index 04ec4fd..fe10171 100644</span><br><span>--- a/src/poll_controller.cpp</span><br><span>+++ b/src/poll_controller.cpp</span><br><span>@@ -51,7 +51,6 @@</span><br><span> {</span><br><span>        struct gprs_rlcmac_dl_tbf *dl_tbf;</span><br><span>   struct gprs_rlcmac_ul_tbf *ul_tbf;</span><br><span style="color: hsl(0, 100%, 40%);">-      struct gprs_rlcmac_sba *sba, *sba2;</span><br><span>  struct llist_item *pos;</span><br><span> </span><br><span>  llist_for_each_entry(pos, &m_bts.ul_tbfs, list) {</span><br><span>@@ -68,11 +67,4 @@</span><br><span>                           dl_tbf->poll_timeout();</span><br><span>           }</span><br><span>    }</span><br><span style="color: hsl(0, 100%, 40%);">-       llist_for_each_entry_safe(sba, sba2, &bts_sba(&m_bts)->m_sbas, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-               if (elapsed_fn_check(max_delay, frame_number, sba->fn)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    /* sba will be freed here */</span><br><span style="color: hsl(0, 100%, 40%);">-                    bts_sba(&m_bts)->timeout(sba);</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> }</span><br><span>diff --git a/src/sba.c b/src/sba.c</span><br><span>new file mode 100644</span><br><span>index 0000000..6706fa3</span><br><span>--- /dev/null</span><br><span>+++ b/src/sba.c</span><br><span>@@ -0,0 +1,83 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* sba.cpp</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2012 Ivan Klyuchnikov</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu></span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2013 by Holger Hans Peter Freyther</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%);">+#include <sba.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <gprs_debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pcu_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pdch.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></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/gsm/protocol/gsm_04_08.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "pdch.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "pdch_ul_controller.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* starting time for assigning single slot</span><br><span style="color: hsl(120, 100%, 40%);">+ * This offset must be a multiple of 13. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define AGCH_START_OFFSET 52</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_sba *sba_alloc(void *ctx, struct gprs_rlcmac_pdch *pdch, uint8_t ta)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_rlcmac_sba *sba;</span><br><span style="color: hsl(120, 100%, 40%);">+  sba = talloc_zero(ctx, struct gprs_rlcmac_sba);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!sba)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        sba->pdch = pdch;</span><br><span style="color: hsl(120, 100%, 40%);">+  sba->ta = ta;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* TODO: request ULC for next available FN instead of hardcoded AGCH_START_OFFSET */</span><br><span style="color: hsl(120, 100%, 40%);">+  sba->fn = next_fn(pdch->last_rts_fn, AGCH_START_OFFSET);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      pdch_ulc_reserve_sba(pdch->ulc, sba);</span><br><span style="color: hsl(120, 100%, 40%);">+      return sba;</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 sba_free(struct gprs_rlcmac_sba *sba)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (pdch_ulc_release_fn(sba->pdch->ulc, sba->fn) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPDCH(sba->pdch, DRLCMAC, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "Trying to release unregistered SBA (FN=%u, TA=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      sba->fn, sba->ta);</span><br><span style="color: hsl(120, 100%, 40%);">+      bts_do_rate_ctr_inc(sba->pdch->trx->bts, CTR_SBA_FREED);</span><br><span style="color: hsl(120, 100%, 40%);">+     talloc_free(sba);</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%);">+uint32_t find_sba_rts(struct gprs_rlcmac_pdch *pdch, uint32_t fn, uint8_t block_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t sba_fn = fn + 4;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_rlcmac_sba *sba;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* check special TBF for events */</span><br><span style="color: hsl(120, 100%, 40%);">+    if ((block_nr % 3) == 2)</span><br><span style="color: hsl(120, 100%, 40%);">+              sba_fn++;</span><br><span style="color: hsl(120, 100%, 40%);">+     sba_fn = sba_fn % GSM_MAX_FN;</span><br><span style="color: hsl(120, 100%, 40%);">+ sba = pdch_ulc_get_sba(pdch->ulc, sba_fn);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sba)</span><br><span style="color: hsl(120, 100%, 40%);">+              return sba_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0xffffffff;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/sba.cpp b/src/sba.cpp</span><br><span>deleted file mode 100644</span><br><span>index 53eb847..0000000</span><br><span>--- a/src/sba.cpp</span><br><span>+++ /dev/null</span><br><span>@@ -1,157 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-/* sba.cpp</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * Copyright (C) 2012 Ivan Klyuchnikov</span><br><span style="color: hsl(0, 100%, 40%);">- * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu></span><br><span style="color: hsl(0, 100%, 40%);">- * Copyright (C) 2013 by Holger Hans Peter Freyther</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%);">-#include <sba.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <gprs_debug.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <bts.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <pcu_utils.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <pdch.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/logging.h></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/gsm/protocol/gsm_04_08.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/gsm/gsm_utils.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%);">-#include <errno.h></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%);">-/* starting time for assigning single slot</span><br><span style="color: hsl(0, 100%, 40%);">- * This offset must be a multiple of 13. */</span><br><span style="color: hsl(0, 100%, 40%);">-#define AGCH_START_OFFSET 52</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-SBAController::SBAController(struct gprs_rlcmac_bts &bts)</span><br><span style="color: hsl(0, 100%, 40%);">-   : m_bts(bts)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   INIT_LLIST_HEAD(&m_sbas);</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 SBAController::alloc(</span><br><span style="color: hsl(0, 100%, 40%);">-         uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t 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%);">-        struct gprs_rlcmac_pdch *pdch;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gprs_rlcmac_sba *sba;</span><br><span style="color: hsl(0, 100%, 40%);">-    int8_t trx, ts;</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t fn;</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%);">-             return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- sba = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_sba);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!sba)</span><br><span style="color: hsl(0, 100%, 40%);">-               return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- for (trx = 0; trx < 8; trx++) {</span><br><span style="color: hsl(0, 100%, 40%);">-              for (ts = 7; ts >= 0; ts--) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        pdch = &m_bts.trx[trx].pdch[ts];</span><br><span style="color: hsl(0, 100%, 40%);">-                    if (!pdch->is_enabled())</span><br><span style="color: hsl(0, 100%, 40%);">-                             continue;</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%);">-               if (ts >= 0)</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%);">-       if (trx == 8) {</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-           talloc_free(sba);</span><br><span style="color: hsl(0, 100%, 40%);">-               return -EINVAL;</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%);">-       fn = next_fn(pdch->last_rts_fn, AGCH_START_OFFSET);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  sba->trx_no = trx;</span><br><span style="color: hsl(0, 100%, 40%);">-   sba->ts_no = ts;</span><br><span style="color: hsl(0, 100%, 40%);">-     sba->fn = fn;</span><br><span style="color: hsl(0, 100%, 40%);">-        sba->ta = ta;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        llist_add(&sba->list, &m_sbas);</span><br><span style="color: hsl(0, 100%, 40%);">-      bts_do_rate_ctr_inc(&m_bts, CTR_SBA_ALLOCATED);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     *_trx = trx;</span><br><span style="color: hsl(0, 100%, 40%);">-    *_ts = ts;</span><br><span style="color: hsl(0, 100%, 40%);">-      *_fn = fn;</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-gprs_rlcmac_sba *SBAController::find(uint8_t trx, uint8_t ts, uint32_t fn)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gprs_rlcmac_sba *sba;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    llist_for_each_entry(sba, &m_sbas, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-          if (sba->trx_no == trx && sba->ts_no == ts && sba->fn == fn)</span><br><span style="color: hsl(0, 100%, 40%);">-                   return sba;</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 style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-gprs_rlcmac_sba *SBAController::find(const gprs_rlcmac_pdch *pdch, uint32_t fn)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   return find(pdch->trx_no(), pdch->ts_no, fn);</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%);">-uint32_t SBAController::sched(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      uint32_t sba_fn = fn + 4;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct gprs_rlcmac_sba *sba;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* check special TBF for events */</span><br><span style="color: hsl(0, 100%, 40%);">-      if ((block_nr % 3) == 2)</span><br><span style="color: hsl(0, 100%, 40%);">-                sba_fn++;</span><br><span style="color: hsl(0, 100%, 40%);">-       sba_fn = sba_fn % GSM_MAX_FN;</span><br><span style="color: hsl(0, 100%, 40%);">-   sba = find(trx, ts, sba_fn);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (sba)</span><br><span style="color: hsl(0, 100%, 40%);">-                return sba_fn;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  return 0xffffffff;</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 SBAController::timeout(struct gprs_rlcmac_sba *sba)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     LOGP(DRLCMAC, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-           "Poll timeout for SBA (TRX=%u, TS=%u, FN=%u, TA=%u)\n", sba->trx_no,</span><br><span style="color: hsl(0, 100%, 40%);">-       sba->ts_no, sba->fn, sba->ta);</span><br><span style="color: hsl(0, 100%, 40%);">-    bts_do_rate_ctr_inc(&m_bts, CTR_SBA_TIMEDOUT);</span><br><span style="color: hsl(0, 100%, 40%);">-      free_sba(sba);</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void SBAController::free_sba(gprs_rlcmac_sba *sba)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   bts_do_rate_ctr_inc(&m_bts, CTR_SBA_FREED);</span><br><span style="color: hsl(0, 100%, 40%);">- llist_del(&sba->list);</span><br><span style="color: hsl(0, 100%, 40%);">-   talloc_free(sba);</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 SBAController::free_resources(struct gprs_rlcmac_pdch *pdch)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gprs_rlcmac_sba *sba, *sba2;</span><br><span style="color: hsl(0, 100%, 40%);">-     const uint8_t trx_no = pdch->trx->trx_no;</span><br><span style="color: hsl(0, 100%, 40%);">- const uint8_t ts_no = pdch->ts_no;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   llist_for_each_entry_safe(sba, sba2, &m_sbas, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-               if (sba->trx_no == trx_no && sba->ts_no == ts_no)</span><br><span style="color: hsl(0, 100%, 40%);">-                 free_sba(sba);</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span>diff --git a/src/sba.h b/src/sba.h</span><br><span>index a6e3f82..446e2ff 100644</span><br><span>--- a/src/sba.h</span><br><span>+++ b/src/sba.h</span><br><span>@@ -20,48 +20,30 @@</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 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%);">+</span><br><span> #include <stdint.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-extern "C" {</span><br><span> #include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct gprs_rlcmac_bts;</span><br><span> struct gprs_rlcmac_pdch;</span><br><span> </span><br><span> /*</span><br><span>  * single block allocation entry</span><br><span>  */</span><br><span> struct gprs_rlcmac_sba {</span><br><span style="color: hsl(0, 100%, 40%);">- struct llist_head list;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t trx_no;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t ts_no;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_rlcmac_pdch *pdch; /* PDCH where the SBA is allocated on*/</span><br><span>       uint32_t fn;</span><br><span>         uint8_t ta;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/**</span><br><span style="color: hsl(0, 100%, 40%);">- * I help to manage SingleBlockAssignment (SBA).</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * TODO: Add a flush method..</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-struct SBAController {</span><br><span style="color: hsl(0, 100%, 40%);">-        friend class PollController;</span><br><span style="color: hsl(0, 100%, 40%);">-public:</span><br><span style="color: hsl(0, 100%, 40%);">-     SBAController(struct gprs_rlcmac_bts &bts);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_sba *sba_alloc(void *ctx, struct gprs_rlcmac_pdch *pdch, uint8_t ta);</span><br><span style="color: hsl(120, 100%, 40%);">+void sba_free(struct gprs_rlcmac_sba *sba);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      int alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta);</span><br><span style="color: hsl(0, 100%, 40%);">-      gprs_rlcmac_sba *find(uint8_t trx, uint8_t ts, uint32_t fn);</span><br><span style="color: hsl(0, 100%, 40%);">-    gprs_rlcmac_sba *find(const gprs_rlcmac_pdch *pdch, uint32_t fn);</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t find_sba_rts(struct gprs_rlcmac_pdch *pdch, uint32_t fn, uint8_t block_nr);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     uint32_t sched(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- int timeout(struct gprs_rlcmac_sba *sba);</span><br><span style="color: hsl(0, 100%, 40%);">-       void free_resources(struct gprs_rlcmac_pdch *pdch);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     void free_sba(gprs_rlcmac_sba *sba);</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%);">-    struct gprs_rlcmac_bts &m_bts;</span><br><span style="color: hsl(0, 100%, 40%);">-      llist_head m_sbas;</span><br><span style="color: hsl(0, 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/tbf.cpp b/src/tbf.cpp</span><br><span>index 15d3fa1..4c94960 100644</span><br><span>--- a/src/tbf.cpp</span><br><span>+++ b/src/tbf.cpp</span><br><span>@@ -562,7 +562,7 @@</span><br><span>           LOGPTBF(this, LOGL_DEBUG, "Polling is already scheduled\n");</span><br><span>               return -EBUSY;</span><br><span>       }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (bts_sba(bts)->find(trx->trx_no, ts, new_poll_fn)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!pdch_ulc_fn_is_free(trx->pdch[ts].ulc, new_poll_fn)) {</span><br><span>               LOGPTBF(this, LOGL_DEBUG, "Polling is already scheduled "</span><br><span>                  "for single block allocation at FN %d TS %d ...\n",</span><br><span>                        new_poll_fn, ts);</span><br><span>diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp</span><br><span>index d921cbe..f7524c9 100644</span><br><span>--- a/tests/tbf/TbfTest.cpp</span><br><span>+++ b/tests/tbf/TbfTest.cpp</span><br><span>@@ -1793,7 +1793,7 @@</span><br><span>    */</span><br><span>  rc = bts_handle_rach(bts, 0x70, rach_fn, qta);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(rc == -EINVAL);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(rc == -EBUSY);</span><br><span> </span><br><span>       TALLOC_FREE(the_pcu);</span><br><span>        fprintf(stderr, "=== end %s ===\n", __func__);</span><br><span>diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err</span><br><span>index c3fff2d..dbf09d0 100644</span><br><span>--- a/tests/tbf/TbfTest.err</span><br><span>+++ b/tests/tbf/TbfTest.err</span><br><span>@@ -6232,7 +6232,7 @@</span><br><span> MS requests Uplink resource on CCCH/RACH: ra=0x70 (8 bit) Fn=2654167 qta=31</span><br><span> MS requests single block allocation</span><br><span> No PDCH available.</span><br><span style="color: hsl(0, 100%, 40%);">-No PDCH resource for single block allocation: rc=-22</span><br><span style="color: hsl(120, 100%, 40%);">+No PDCH resource for single block allocation</span><br><span> Tx Immediate Assignment Reject on AGCH</span><br><span> === end test_immediate_assign_rej_single_block ===</span><br><span> === start test_tbf_egprs_two_phase_puan ===</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-pcu/+/23291">change 23291</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/+/23291"/><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: I84b24beea4a1aa2c1528f41435f77bd16df2b947 </div>
<div style="display:none"> Gerrit-Change-Number: 23291 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>