aboutsummaryrefslogtreecommitdiffstats
path: root/src/tbf_ul.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tbf_ul.cpp')
-rw-r--r--src/tbf_ul.cpp237
1 files changed, 116 insertions, 121 deletions
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 74b2636b..3746130f 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -13,10 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <bts.h>
@@ -33,6 +29,7 @@
#include <gprs_ms.h>
#include <llc.h>
#include "pcu_utils.h"
+#include "alloc_algo.h"
extern "C" {
#include <osmocom/core/msgb.h>
@@ -108,10 +105,9 @@ static int ul_tbf_dtor(struct gprs_rlcmac_ul_tbf *tbf)
}
/* Generic function to alloc a UL TBF, later configured to be assigned either over CCCH or PACCH */
-struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts, GprsMs *ms, int8_t use_trx, bool single_slot)
+struct gprs_rlcmac_ul_tbf *ul_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms)
{
struct gprs_rlcmac_ul_tbf *tbf;
- int rc;
OSMO_ASSERT(ms != NULL);
@@ -124,122 +120,38 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts, GprsMs
talloc_set_destructor(tbf, ul_tbf_dtor);
new (tbf) gprs_rlcmac_ul_tbf(bts, ms);
- rc = tbf->setup(use_trx, single_slot);
-
- /* if no resource */
- if (rc < 0) {
- talloc_free(tbf);
- return NULL;
- }
-
- if (tbf->is_egprs_enabled())
- tbf->set_window_size();
-
- tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(tbf,
- &tbf_ul_egprs_ctrg_desc, tbf->m_ctrs->idx);
- tbf->m_ul_gprs_ctrs = rate_ctr_group_alloc(tbf,
- &tbf_ul_gprs_ctrg_desc, tbf->m_ctrs->idx);
- if (!tbf->m_ul_egprs_ctrs || !tbf->m_ul_gprs_ctrs) {
- LOGPTBF(tbf, LOGL_ERROR, "Couldn't allocate TBF UL counters\n");
- talloc_free(tbf);
- return NULL;
- }
-
- llist_add_tail(tbf_trx_list(tbf), &tbf->trx->ul_tbfs);
bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_UL_ALLOCATED);
return tbf;
}
-/* Alloc a UL TBF to be assigned over PACCH */
-gprs_rlcmac_ul_tbf *tbf_alloc_ul_pacch(struct gprs_rlcmac_bts *bts, GprsMs *ms, int8_t use_trx)
-{
- struct gprs_rlcmac_ul_tbf *tbf;
-
- tbf = tbf_alloc_ul_tbf(bts, ms, use_trx, false);
- if (!tbf) {
- LOGPMS(ms, DTBF, LOGL_NOTICE, "No PDCH resource\n");
- /* Caller will most probably send a Imm Ass Reject after return */
- return NULL;
- }
- tbf->m_contention_resolution_done = 1;
- osmo_fsm_inst_dispatch(tbf->state_fsm.fi, TBF_EV_ASSIGN_ADD_PACCH, NULL);
-
- return tbf;
-}
-
-/* Alloc a UL TBF to be assigned over CCCH */
-struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_ccch(struct gprs_rlcmac_bts *bts, struct GprsMs *ms)
-{
- struct gprs_rlcmac_ul_tbf *tbf;
-
- tbf = tbf_alloc_ul_tbf(bts, ms, -1, true);
- if (!tbf) {
- LOGP(DTBF, LOGL_NOTICE, "No PDCH resource for Uplink TBF\n");
- /* Caller will most probably send a Imm Ass Reject after return */
- return NULL;
- }
- osmo_fsm_inst_dispatch(tbf->state_fsm.fi, TBF_EV_ASSIGN_ADD_CCCH, NULL);
- tbf->contention_resolution_start();
- OSMO_ASSERT(tbf->ms());
-
- return tbf;
-}
-
-/* Create a temporary dummy TBF to Tx a ImmAssReject if allocating a new one during
- * packet resource Request failed. This is similar as tbf_alloc_ul() but without
- * calling tbf->setup() (in charge of TFI/USF allocation), and reusing resources
- * from Packet Resource Request we received. See TS 44.060 sec 7.1.3.2.1 */
-struct gprs_rlcmac_ul_tbf *handle_tbf_reject(struct gprs_rlcmac_bts *bts,
- GprsMs *ms, uint8_t trx_no, uint8_t ts)
-{
- struct gprs_rlcmac_ul_tbf *ul_tbf = NULL;
- struct gprs_rlcmac_trx *trx = &bts->trx[trx_no];
- OSMO_ASSERT(ms);
-
- ul_tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
- if (!ul_tbf)
- return ul_tbf;
- talloc_set_destructor(ul_tbf, ul_tbf_dtor);
- new (ul_tbf) gprs_rlcmac_ul_tbf(bts, ms);
-
- ul_tbf->control_ts = ts;
- ul_tbf->trx = trx;
- ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, next_tbf_ctr_group_id++);
- ul_tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(ul_tbf,
- &tbf_ul_egprs_ctrg_desc,
- ul_tbf->m_ctrs->idx);
- ul_tbf->m_ul_gprs_ctrs = rate_ctr_group_alloc(ul_tbf,
- &tbf_ul_gprs_ctrg_desc,
- ul_tbf->m_ctrs->idx);
- if (!ul_tbf->m_ctrs || !ul_tbf->m_ul_egprs_ctrs || !ul_tbf->m_ul_gprs_ctrs) {
- LOGPTBF(ul_tbf, LOGL_ERROR, "Cound not allocate TBF UL rate counters\n");
- talloc_free(ul_tbf);
- return NULL;
- }
-
- ms_attach_tbf(ms, ul_tbf);
- llist_add(tbf_trx_list((struct gprs_rlcmac_tbf *)ul_tbf), &trx->ul_tbfs);
- bts_do_rate_ctr_inc(ul_tbf->bts, CTR_TBF_UL_ALLOCATED);
- osmo_fsm_inst_dispatch(ul_tbf->state_fsm.fi, TBF_EV_ASSIGN_ADD_PACCH, NULL);
- osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS_REJ, NULL);
-
- return ul_tbf;
-}
-
gprs_rlcmac_ul_tbf::gprs_rlcmac_ul_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms) :
gprs_rlcmac_tbf(bts_, ms, GPRS_RLCMAC_UL_TBF),
m_rx_counter(0),
- m_contention_resolution_done(0),
+ m_contention_resolution_done(true),
m_ul_gprs_ctrs(NULL),
m_ul_egprs_ctrs(NULL)
{
memset(&m_usf, USF_INVALID, sizeof(m_usf));
+ memset(&state_fsm, 0, sizeof(state_fsm));
+ state_fsm.ul_tbf = this;
+ state_fi = osmo_fsm_inst_alloc(&tbf_ul_fsm, this, &state_fsm, LOGL_INFO, NULL);
+ OSMO_ASSERT(state_fi);
+
memset(&ul_ack_fsm, 0, sizeof(ul_ack_fsm));
ul_ack_fsm.tbf = this;
ul_ack_fsm.fi = osmo_fsm_inst_alloc(&tbf_ul_ack_fsm, this, &ul_ack_fsm, LOGL_INFO, NULL);
+ m_ul_egprs_ctrs = rate_ctr_group_alloc(this, &tbf_ul_egprs_ctrg_desc, m_ctrs->idx);
+ OSMO_ASSERT(m_ul_egprs_ctrs);
+ m_ul_gprs_ctrs = rate_ctr_group_alloc(this, &tbf_ul_gprs_ctrg_desc, m_ctrs->idx);
+ OSMO_ASSERT(m_ul_gprs_ctrs);
+
+ /* This has to be called in child constructor because enable_egprs()
+ * uses the window() virtual function which is dependent on subclass. */
+ if (ms_mode(m_ms) != GPRS)
+ enable_egprs();
}
/*
@@ -276,7 +188,7 @@ int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
i + 1, frame->offset, frame->length,
frame->is_complete);
- m_llc.append_frame(data + frame->offset, frame->length);
+ llc_append_frame(&m_llc, data + frame->offset, frame->length);
llc_consume(&m_llc, frame->length);
}
@@ -285,13 +197,14 @@ int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
LOGPTBFUL(this, LOGL_DEBUG, "complete UL frame len=%d\n", llc_frame_length(&m_llc));
snd_ul_ud();
bts_do_rate_ctr_add(bts, CTR_LLC_UL_BYTES, llc_frame_length(&m_llc));
- m_llc.reset();
+ llc_reset(&m_llc);
}
}
return 0;
}
+/* 3GPP TS 44.060 sec 7a.2.1 Contention Resolution */
void gprs_rlcmac_ul_tbf::contention_resolution_start()
{
/* 3GPP TS 44.018 sec 11.1.2 Timers on the network side: "This timer is
@@ -304,23 +217,29 @@ void gprs_rlcmac_ul_tbf::contention_resolution_start()
* timeout only for one-phase packet access, since two-phase is handled
* through SBA structs, which are freed by the PDCH UL Controller if the
* single allocated block is lost. */
+ m_contention_resolution_done = false;
T_START(this, T3141, 3141, "Contention resolution (UL-TBF, CCCH)", true);
}
void gprs_rlcmac_ul_tbf::contention_resolution_success()
{
- if (m_contention_resolution_done)
- return;
+ /* now we must set this flag, so we are allowed to assign downlink
+ * TBF on PACCH. it is only allowed when TLLI is acknowledged
+ * (3GPP TS 44.060 sec 7.1.3.1). */
+ m_contention_resolution_done = true;
- /* 3GPP TS 44.060 sec 7a.2.1 Contention Resolution */
/* 3GPP TS 44.018 3.5.2.1.4 Packet access completion: The one phase
packet access procedure is completed at a successful contention
resolution. The mobile station has entered the packet transfer mode.
Timer T3141 is stopped on the network side */
t_stop(T3141, "Contention resolution success (UL-TBF, CCCH)");
- /* now we must set this flag, so we are allowed to assign downlink
- * TBF on PACCH. it is only allowed when TLLI is acknowledged. */
- m_contention_resolution_done = 1;
+ bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_UL_TBF_CONTENTION_RESOLUTION_SUCCESS);
+
+ /* Check if we can create a DL TBF to start sending the enqueued
+ * data. Otherwise it will be triggered later when it is reachable
+ * again. */
+ if (ms_need_dl_tbf(ms()) && !tbf_ul_ack_waiting_cnf_final_ack(this))
+ ms_new_dl_tbf_assigned_on_pacch(ms(), this);
}
/*! \brief receive data from PDCH/L1 */
@@ -339,6 +258,19 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
"V(R)=%d)\n", rlc->tfi, this->m_window.v_q(),
this->m_window.v_r());
+ if (tbf_state(this) == TBF_ST_RELEASING) {
+ /* This may happen if MAX_N3101 is hit previously, moving the UL
+ * TBF to RELEASING state. Since we have an fn-advance where DL
+ * blocks are scheduled in advance, we may have requested USF for
+ * this UL TBF before triggering and hence we are now receiving a
+ * UL block from it. If this is the case, simply ignore the block.
+ */
+ LOGPTBFUL(this, LOGL_INFO,
+ "UL DATA TFI=%d received (V(Q)=%d .. V(R)=%d) while in RELEASING state, discarding\n",
+ rlc->tfi, this->m_window.v_q(), this->m_window.v_r());
+ return 0;
+ }
+
/* process RSSI */
gprs_rlcmac_rssi(this, rssi);
@@ -371,7 +303,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
rdbi->bsn,
m_window.v_q(), m_window.mod_sns(m_window.v_q() + ws - 1));
continue;
- } else if (m_window.is_received(rdbi->bsn)) {
+ } else if (m_window.m_v_n.is_received(rdbi->bsn)) {
LOGPTBFUL(this, LOGL_DEBUG,
"BSN %d already received\n", rdbi->bsn);
continue;
@@ -429,8 +361,8 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
LOGPTBFUL(this, LOGL_INFO,
"Decoded premier TLLI=0x%08x of UL DATA TFI=%d.\n",
new_tlli, rlc->tfi);
- update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
- bts_pch_timer_stop(bts, ms_imsi(ms()));
+ ms_update_announced_tlli(ms(), new_tlli);
+ osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_FIRST_UL_DATA_RECVD, NULL);
} else if (new_tlli != GSM_RESERVED_TMSI && new_tlli != tlli()) {
LOGPTBFUL(this, LOGL_NOTICE,
"Decoded TLLI=%08x mismatch on UL DATA TFI=%d. (Ignoring due to contention resolution)\n",
@@ -472,7 +404,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
rdbi->bsn, rdbi->cv);
if (rdbi->cv == 0) {
LOGPTBFUL(this, LOGL_DEBUG, "Finished with UL TBF\n");
- osmo_fsm_inst_dispatch(this->state_fsm.fi, TBF_EV_LAST_UL_DATA_RECVD, NULL);
+ osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_LAST_UL_DATA_RECVD, NULL);
/* Reset N3103 counter. */
this->n_reset(N3103);
}
@@ -535,7 +467,7 @@ int gprs_rlcmac_ul_tbf::snd_ul_ud()
LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] %s len=%d\n", tbf_name(this), llc_frame_length(&m_llc));
if (!bctx) {
LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
- m_llc.reset_frame_space();
+ llc_reset_frame_space(&m_llc);
return -EIO;
}
@@ -547,7 +479,7 @@ int gprs_rlcmac_ul_tbf::snd_ul_ud()
qos_profile[2] = QOS_PROFILE;
bssgp_tx_ul_ud(bctx, tlli(), qos_profile, llc_pdu);
- m_llc.reset_frame_space();
+ llc_reset_frame_space(&m_llc);
return 0;
}
@@ -743,13 +675,63 @@ gprs_rlc_window *gprs_rlcmac_ul_tbf::window()
return &m_window;
}
+void gprs_rlcmac_ul_tbf::apply_allocated_resources(const struct alloc_resources_res *res)
+{
+ uint8_t ts;
+
+ if (this->trx)
+ llist_del(&this->m_trx_list.list);
+
+ llist_add(&this->m_trx_list.list, &res->trx->ul_tbfs);
+
+ this->trx = res->trx;
+ this->upgrade_to_multislot = res->upgrade_to_multislot;
+
+ for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
+ struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
+ OSMO_ASSERT(!this->pdch[pdch->ts_no]);
+ if (!(res->ass_slots_mask & (1 << ts)))
+ continue;
+ LOGPTBFUL(this, LOGL_DEBUG, "Assigning TS=%u TFI=%d USF=%u\n",
+ ts, res->tfi, res->usf[ts]);
+ OSMO_ASSERT(res->usf[ts] >= 0);
+
+ this->m_tfi = res->tfi;
+ this->m_usf[pdch->ts_no] = res->usf[ts];
+
+ this->pdch[pdch->ts_no] = pdch;
+ pdch->attach_tbf(this);
+ }
+
+ /* assign initial control ts */
+ tbf_assign_control_ts(this);
+
+ /* res.ass_slots_mask == 0 -> special case for Rejected UL TBFs,
+ * see ms_new_ul_tbf_rejected_pacch() */
+ if (res->ass_slots_mask != 0) {
+ LOGPTBF(this, LOGL_INFO,
+ "Allocated: trx = %d, ul_slots = %02x, dl_slots = %02x\n",
+ this->trx->trx_no, ul_slots(), dl_slots());
+
+ if (tbf_is_egprs_enabled(this))
+ this->set_window_size();
+ }
+
+ tbf_update_state_fsm_name(this);
+}
+
+void ul_tbf_apply_allocated_resources(struct gprs_rlcmac_ul_tbf *ul_tbf, const struct alloc_resources_res *res)
+{
+ ul_tbf->apply_allocated_resources(res);
+}
+
void gprs_rlcmac_ul_tbf::usf_timeout()
{
if (n_inc(N3101))
- osmo_fsm_inst_dispatch(this->state_fsm.fi, TBF_EV_MAX_N3101, NULL);
+ osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_MAX_N3101, NULL);
}
-struct gprs_rlcmac_ul_tbf *as_ul_tbf(struct gprs_rlcmac_tbf *tbf)
+struct gprs_rlcmac_ul_tbf *tbf_as_ul_tbf(struct gprs_rlcmac_tbf *tbf)
{
if (tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
return static_cast<gprs_rlcmac_ul_tbf *>(tbf);
@@ -757,6 +739,14 @@ struct gprs_rlcmac_ul_tbf *as_ul_tbf(struct gprs_rlcmac_tbf *tbf)
return NULL;
}
+const struct gprs_rlcmac_ul_tbf *tbf_as_ul_tbf_const(const struct gprs_rlcmac_tbf *tbf)
+{
+ if (tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
+ return static_cast<const gprs_rlcmac_ul_tbf *>(tbf);
+ else
+ return NULL;
+}
+
void tbf_usf_timeout(struct gprs_rlcmac_ul_tbf *tbf)
{
tbf->usf_timeout();
@@ -773,6 +763,11 @@ struct osmo_fsm_inst *tbf_ul_ack_fi(const struct gprs_rlcmac_ul_tbf *tbf)
return tbf->ul_ack_fsm.fi;
}
+void ul_tbf_contention_resolution_start(struct gprs_rlcmac_ul_tbf *tbf)
+{
+ tbf->contention_resolution_start();
+}
+
void ul_tbf_contention_resolution_success(struct gprs_rlcmac_ul_tbf *tbf)
{
return tbf->contention_resolution_success();