diff options
Diffstat (limited to 'src/tbf_ul.cpp')
-rw-r--r-- | src/tbf_ul.cpp | 237 |
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(); |