diff options
Diffstat (limited to 'src/pdch.cpp')
-rw-r--r-- | src/pdch.cpp | 471 |
1 files changed, 280 insertions, 191 deletions
diff --git a/src/pdch.cpp b/src/pdch.cpp index 5d8658af..7ff1c7e6 100644 --- a/src/pdch.cpp +++ b/src/pdch.cpp @@ -5,8 +5,8 @@ * All Rights Reserved * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -14,7 +14,7 @@ * 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 Affero General Public License + * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ @@ -27,7 +27,6 @@ #include <gprs_debug.h> #include <coding_scheme.h> #include <gprs_ms.h> -#include <gprs_ms_storage.h> #include <pcu_l1_if.h> #include <rlc.h> #include <sba.h> @@ -119,18 +118,44 @@ static inline void sched_ul_ass_or_rej(struct gprs_rlcmac_bts *bts, struct gprs_ bts_do_rate_ctr_inc(bts, CTR_CHANNEL_REQUEST_DESCRIPTION); /* This call will register the new TBF with the MS on success */ - gprs_rlcmac_ul_tbf *ul_tbf = tbf_alloc_ul_pacch(bts, tbf->ms(), tbf->trx->trx_no); + gprs_rlcmac_ul_tbf *ul_tbf = ms_new_ul_tbf_assigned_pacch(tbf->ms(), tbf->trx->trx_no); /* schedule uplink assignment or reject */ if (ul_tbf) { - LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack message, so we provide one:\n"); + LOGPTBFDL(tbf, LOGL_DEBUG, "MS requests UL TBF in ack message, so we provide one:\n"); osmo_fsm_inst_dispatch(tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS, NULL); } else { - LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack message, so we packet access reject:\n"); + LOGPTBFDL(tbf, LOGL_NOTICE, "MS requests UL TBF in ack message, but alloc failed: send PktAssRej\n"); osmo_fsm_inst_dispatch(tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS_REJ, NULL); } } +/* Make sure the PDCH vanished from the mask of reserved PDCHs for all MS, to + * avoid alloc_algorithm using it. */ +static void pdch_unreserve_all_ms_reserved_slots(struct gprs_rlcmac_pdch *pdch) +{ + struct llist_head *tmp; + uint8_t ts_rm_mask = (~(1 << pdch->ts_no)); + struct gprs_rlcmac_trx *trx = pdch->trx; + + llist_for_each(tmp, &trx->bts->ms_list) { + struct GprsMs *ms = llist_entry(tmp, typeof(*ms), list); + if (ms->current_trx != trx) + continue; + uint8_t old_dl_slots = ms_reserved_dl_slots(ms); + uint8_t old_ul_slots = ms_reserved_ul_slots(ms); + uint8_t new_dl_slots = old_dl_slots & ts_rm_mask; + uint8_t new_ul_slots = old_ul_slots & ts_rm_mask; + if (old_dl_slots == new_dl_slots && old_ul_slots == new_ul_slots) + continue; + ms_set_reserved_slots(ms, trx, new_ul_slots, new_dl_slots); + } + if (pdch->num_reserved(GPRS_RLCMAC_UL_TBF) > 0 || pdch->num_reserved(GPRS_RLCMAC_DL_TBF) > 0) + LOGPDCH(pdch, DRLCMAC, LOGL_ERROR, + "Reserved TS count not zero after unreserving from all current MS in list! UL=%u DL=%u\n", + pdch->num_reserved(GPRS_RLCMAC_UL_TBF), pdch->num_reserved(GPRS_RLCMAC_DL_TBF)); +} + void pdch_init(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_trx *trx, uint8_t ts_nr) { pdch->ts_no = ts_nr; @@ -143,6 +168,7 @@ void pdch_init(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_trx *trx, uint8 void gprs_rlcmac_pdch::enable() { + LOGPDCH(this, DRLCMAC, LOGL_INFO, "PDCH state: %s => enabled\n", m_is_enabled ? "enabled" : "disabled"); OSMO_ASSERT(m_is_enabled == 0); INIT_LLIST_HEAD(&paging_list); @@ -155,6 +181,7 @@ void gprs_rlcmac_pdch::enable() void gprs_rlcmac_pdch::disable() { + LOGPDCH(this, DRLCMAC, LOGL_INFO, "PDCH state: %s => disabled\n", m_is_enabled ? "enabled" : "disabled"); OSMO_ASSERT(m_is_enabled == 1); this->free_resources(); @@ -169,6 +196,8 @@ void gprs_rlcmac_pdch::free_resources() /* kick all TBF on slot */ pdch_free_all_tbf(this); + pdch_unreserve_all_ms_reserved_slots(this); + /* flush all pending paging messages */ while ((pag = dequeue_paging())) talloc_free(pag); @@ -315,30 +344,20 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, poll = pdch_ulc_get_node(ulc, fn); if (!poll || poll->type != PDCH_ULC_NODE_TBF_POLL) { - LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with " - "unknown FN=%u TLLI=0x%08x (TRX %d TS %d)\n", - fn, tlli, trx_no(), ts_no); - ms = bts_ms_by_tlli(bts(), tlli, GSM_RESERVED_TMSI); + LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with unknown FN=%u TLLI=0x%08x\n", + fn, tlli); + ms = bts_get_ms_by_tlli(bts(), tlli, GSM_RESERVED_TMSI); if (ms) LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with " - "unknown TBF corresponds to MS with IMSI %s, TA %d, " - "uTBF (TFI=%d, state=%s), dTBF (TFI=%d, state=%s)\n", - ms_imsi(ms), ms_ta(ms), - ms_ul_tbf(ms) ? ms_ul_tbf(ms)->tfi() : 0, - ms_ul_tbf(ms) ? ms_ul_tbf(ms)->state_name() : "None", - ms_dl_tbf(ms) ? ms_dl_tbf(ms)->tfi() : 0, - ms_dl_tbf(ms) ? ms_dl_tbf(ms)->state_name() : "None"); + "unknown TBF corresponds to %s\n", ms_name(ms)); return; } OSMO_ASSERT(poll->tbf_poll.poll_tbf); tbf = poll->tbf_poll.poll_tbf; reason = poll->tbf_poll.reason; - /* Reset N3101 counter: */ - tbf->n_reset(N3101); - - tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF); - /* Gather MS from TBF, since it may be NULL or may have been merged during update_ms */ + ms_update_announced_tlli(tbf->ms(), tlli); + /* Gather MS from TBF again, since it may be NULL or may have been merged during ms_update_announced_tlli */ ms = tbf->ms(); LOGPTBF(tbf, LOGL_DEBUG, "FN=%" PRIu32 " Rx Packet Control Ack (reason=%s)\n", @@ -346,7 +365,7 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, switch (reason) { case PDCH_ULC_POLL_UL_ACK: - ul_tbf = as_ul_tbf(tbf); + ul_tbf = tbf_as_ul_tbf(tbf); OSMO_ASSERT(ul_tbf); if (!tbf_ul_ack_exp_ctrl_ack(ul_tbf, fn, ts_no)) { LOGPTBF(tbf, LOGL_NOTICE, "FN=%d, TS=%d (curr FN %d): POLL_UL_ACK not expected!\n", @@ -355,9 +374,12 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, } pdch_ulc_release_fn(ulc, fn); osmo_fsm_inst_dispatch(ul_tbf->ul_ack_fsm.fi, TBF_UL_ACK_EV_RX_CTRL_ACK, NULL); - /* We only set polling on final UL ACK/NACK */ - LOGPTBF(tbf, LOGL_DEBUG, "[UPLINK] END\n"); - osmo_fsm_inst_dispatch(ul_tbf->state_fsm.fi, TBF_EV_FINAL_UL_ACK_CONFIRMED, NULL); + /* We only set polling on final UL ACK/NACK, something is wrong... */ + if (tbf_state(tbf) == TBF_ST_FINISHED) + osmo_fsm_inst_dispatch(ul_tbf->state_fi, TBF_EV_FINAL_UL_ACK_CONFIRMED, (void*)false); + /* ul_tbf is freed here! */ + else + LOGPTBFUL(ul_tbf, LOGL_ERROR, "Received POLL_UL_ACK for UL TBF in unexpected state!\n"); return; case PDCH_ULC_POLL_UL_ASS: @@ -369,8 +391,8 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, } LOGPTBF(tbf, LOGL_DEBUG, "[DOWNLINK] UPLINK ASSIGNED\n"); pdch_ulc_release_fn(ulc, fn); - /* reset N3105 */ - tbf->n_reset(N3105); + if (tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF) + tbf->n_reset(N3105); osmo_fsm_inst_dispatch(tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_RX_ASS_CTRL_ACK, NULL); new_tbf = ms_ul_tbf(ms); @@ -379,16 +401,13 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, "TBF is gone TLLI=0x%08x\n", tlli); return; } - if (tbf->state_is(TBF_ST_WAIT_RELEASE) && - tbf->direction == new_tbf->direction) - tbf_free(tbf); - osmo_fsm_inst_dispatch(new_tbf->state_fsm.fi, TBF_EV_ASSIGN_ACK_PACCH, NULL); + osmo_fsm_inst_dispatch(new_tbf->state_fi, TBF_EV_ASSIGN_ACK_PACCH, NULL); /* there might be LLC packets waiting in the queue, but the DL * TBF might have been released while the UL TBF has been * established */ if (ms_need_dl_tbf(new_tbf->ms())) - new_tbf->establish_dl_tbf_on_pacch(); + ms_new_dl_tbf_assigned_on_pacch(new_tbf->ms(), new_tbf); return; case PDCH_ULC_POLL_DL_ASS: @@ -400,8 +419,8 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, } LOGPTBF(tbf, LOGL_DEBUG, "[UPLINK] DOWNLINK ASSIGNED\n"); pdch_ulc_release_fn(ulc, fn); - /* reset N3105 */ - tbf->n_reset(N3105); + if (tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF) + tbf->n_reset(N3105); osmo_fsm_inst_dispatch(tbf->dl_ass_fsm.fi, TBF_DL_ASS_EV_RX_ASS_CTRL_ACK, NULL); new_tbf = ms_dl_tbf(ms); @@ -410,11 +429,12 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, "TBF is gone TLLI=0x%08x\n", tlli); return; } - if (tbf->state_is(TBF_ST_WAIT_RELEASE) && - tbf->direction == new_tbf->direction) + if ((tbf->state_is(TBF_ST_WAIT_RELEASE) || + tbf->state_is(TBF_ST_WAIT_REUSE_TFI)) && + tbf->direction == new_tbf->direction) tbf_free(tbf); - osmo_fsm_inst_dispatch(new_tbf->state_fsm.fi, TBF_EV_ASSIGN_ACK_PACCH, NULL); + osmo_fsm_inst_dispatch(new_tbf->state_fi, TBF_EV_ASSIGN_ACK_PACCH, NULL); return; case PDCH_ULC_POLL_CELL_CHG_CONTINUE: @@ -467,16 +487,13 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n return; } OSMO_ASSERT(poll->tbf_poll.poll_tbf); - tbf = as_dl_tbf(poll->tbf_poll.poll_tbf); + tbf = tbf_as_dl_tbf(poll->tbf_poll.poll_tbf); if (tbf->tfi() != tfi) { LOGPTBFDL(tbf, LOGL_NOTICE, "PACKET DOWNLINK ACK with wrong TFI=%d, ignoring!\n", tfi); return; } - /* Reset N3101 counter: */ - tbf->n_reset(N3101); - pdch_ulc_release_fn(ulc, fn); LOGPTBF(tbf, LOGL_DEBUG, "RX: [PCU <- BTS] Packet Downlink Ack/Nack\n"); @@ -537,15 +554,13 @@ void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nac return; } OSMO_ASSERT(poll->tbf_poll.poll_tbf); - tbf = as_dl_tbf(poll->tbf_poll.poll_tbf); + tbf = tbf_as_dl_tbf(poll->tbf_poll.poll_tbf); if (tbf->tfi() != tfi) { LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with " "wrong TFI=%d, ignoring!\n", tfi); return; } - /* Reset N3101 counter: */ - tbf->n_reset(N3101); pdch_ulc_release_fn(ulc, fn); LOGPTBF(tbf, LOGL_DEBUG, @@ -611,157 +626,205 @@ void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nac void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn, struct pcu_l1_meas *meas) { - struct gprs_rlcmac_sba *sba; int rc; + struct gprs_rlcmac_bts *bts = trx->bts; + struct pdch_ulc_node *item; + char buf[128]; + struct GprsMs *ms = NULL; + struct gprs_rlcmac_sba *sba; + struct gprs_rlcmac_dl_tbf *dl_tbf = NULL; + struct gprs_rlcmac_ul_tbf *ul_tbf = NULL; + struct gprs_rlcmac_ul_tbf *new_ul_tbf = NULL; - if (request->ID.UnionType) { - struct gprs_rlcmac_ul_tbf *ul_tbf = NULL; - struct pdch_ulc_node *item; - uint32_t tlli = request->ID.u.TLLI; - GprsMs *ms = bts_ms_by_tlli(bts(), tlli, GSM_RESERVED_TMSI); + if (!(item = pdch_ulc_get_node(ulc, fn))) { + LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " + "UL block not reserved\n", fn); + return; + } + + /* First gather MS from TLLI/DL_TFI/UL_TFI:*/ + if (request->ID.UnionType) { /* ID_TYPE = TLLI */ + uint32_t tlli = request->ID.u.TLLI; + ms = bts_get_ms_by_tlli(bts, tlli, GSM_RESERVED_TMSI); if (!ms) { - ms = bts_alloc_ms(bts(), 0, 0); /* ms class updated later */ + /* A reference is already hold immediately below in all cases, no + * need to hold and extra one, pass use_ref=NULL: */ + ms = ms_alloc(bts, NULL); ms_set_tlli(ms, tlli); } + } else if (request->ID.u.Global_TFI.UnionType) { /* ID_TYPE = DL_TFI */ + int8_t tfi = request->ID.u.Global_TFI.u.DOWNLINK_TFI; + dl_tbf = bts_dl_tbf_by_tfi(bts, tfi, trx_no(), ts_no); + if (!dl_tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESOURCE REQ unknown downlink TFI=%d\n", tfi); + return; + } + ms = tbf_ms(dl_tbf_as_tbf(dl_tbf)); + dl_tbf = NULL; + } else { /* ID_TYPE = UL_TFI */ + int8_t tfi = request->ID.u.Global_TFI.u.UPLINK_TFI; + ul_tbf = bts_ul_tbf_by_tfi(bts, tfi, trx_no(), ts_no); + if (!ul_tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESOURCE REQ unknown uplink TFI=%d\n", tfi); + return; + } + ms = tbf_ms(ul_tbf_as_tbf(ul_tbf)); + ul_tbf = NULL; + } - /* Keep the ms, even if it gets idle temporarily */ - ms_ref(ms); - if (!(item = pdch_ulc_get_node(ulc, fn))) { - LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " - "UL block not reserved\n", fn); - goto return_unref; - } + /* Here ms is available (non-null). Keep the ms, even if it gets idle + * temporarily, in order to avoid it being freed if we free any of its + * resources (TBF). */ + OSMO_ASSERT(ms); + ms_ref(ms, __func__); - switch (item->type) { - case PDCH_ULC_NODE_TBF_USF: - /* Is it actually valid for an MS to send a PKT Res Req during USF? */ - ul_tbf = item->tbf_usf.ul_tbf; + + switch (item->type) { + case PDCH_ULC_NODE_TBF_USF: + /* TS 44.060 to 8.1.1.1.2: An MS can send a PKT Res Req during USF, for instance to change its Radio Priority. */ + ul_tbf = item->tbf_usf.ul_tbf; + if (tbf_ms(ul_tbf_as_tbf(ul_tbf)) != ms) { LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " - "Unexpectedly received, waiting USF of %s\n", - fn, tbf_name(item->tbf_usf.ul_tbf)); - /* Ignore it, let common path expire related ULC entry */ + "Received from unexpected %s vs exp %s\n", fn, + ms_name_buf(ms, buf, sizeof(buf)), ms_name(tbf_ms(ul_tbf_as_tbf(ul_tbf)))); + /* let common path expire the poll */ goto return_unref; - case PDCH_ULC_NODE_SBA: - sba = item->sba.sba; - LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "FN=%u PKT RESOURCE REQ: " - "MS requests UL TBF throguh SBA\n", fn); - ms_set_ta(ms, sba->ta); - sba_free(sba); - break; - case PDCH_ULC_NODE_TBF_POLL: - if (item->tbf_poll.poll_tbf->direction != GPRS_RLCMAC_UL_TBF) { - LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " - "Unexpectedly received for DL TBF %s\n", fn, - tbf_name(item->tbf_poll.poll_tbf)); - /* let common path expire the poll */ - goto return_unref; - } - ul_tbf = (struct gprs_rlcmac_ul_tbf *)item->tbf_poll.poll_tbf; - if (item->tbf_poll.reason != PDCH_ULC_POLL_UL_ACK) { - LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " - "Unexpectedly received, waiting for poll reason %d\n", - fn, item->tbf_poll.reason); - /* let common path expire the poll */ - goto return_unref; - } - if (ul_tbf != ms_ul_tbf(ms)) { - LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " - "Unexpected TLLI 0x%08x received vs exp 0x%08x\n", - fn, tlli, ul_tbf->tlli()); - /* let common path expire the poll */ - goto return_unref; - } - /* 3GPP TS 44.060 $ 9.3.3.3 */ - LOGPTBFUL(ul_tbf, LOGL_DEBUG, "FN=%u PKT RESOURCE REQ: " - "MS requests reuse of finished UL TBF in RRBP " - "block of final UL ACK/NACK\n", fn); - ul_tbf->n_reset(N3103); - pdch_ulc_release_node(ulc, item); - rc = osmo_fsm_inst_dispatch(ul_tbf->state_fsm.fi, TBF_EV_FINAL_UL_ACK_CONFIRMED, NULL); - if (rc) { - /* FSM failed handling, get rid of previous finished UL TBF before providing a new one */ - LOGPTBFUL(ul_tbf, LOGL_NOTICE, - "Got PACKET RESOURCE REQ while TBF not finished, killing pending UL TBF\n"); - tbf_free(ul_tbf); - } /* else: ul_tbf has been freed by state_fsm */ + } + LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " + "MS requests UL TBF upgrade through USF of %s\n", + fn, tbf_name(item->tbf_usf.ul_tbf)); + pdch_ulc_release_node(ulc, item); + /* FIXME OS#4947: Currenty we free the UL TBF and create a new one below in order to trigger the Pkt UL Ass. + * We should instead keep the same UL TBF working and upgrading it (modify ul_tbf->ul_ass_fsm.fi to + * handle the PktUlAss + PktCtrlAck). + * This is required by spec, and MS are know to continue using the TBF (due to delay in between DL and + * UL scheduling). + * TS 44.060 to 8.1.1.1.2: + * "If the mobile station or the network does not support multiple TBF procedures, then after the + * transmission of the PACKET RESOURCE REQUEST message with the reason for changing PFI, the radio + * priority or peak throughput class of an assigned uplink TBF the mobile station continue to use the + * currently assigned uplink TBF assuming that the requested radio priority or peak throughput class is + * already assigned to that TBF." + */ + tbf_free(ul_tbf); + ul_tbf = NULL; + break; + case PDCH_ULC_NODE_SBA: + sba = item->sba.sba; + LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "FN=%u PKT RESOURCE REQ: " + "MS requests UL TBF throguh SBA\n", fn); + ms_set_ta(ms, sba->ta); + sba_free(sba); + /* If MS identified by TLLI sent us a PktResReq through SBA, it means it came + * from CCCH, so it's for sure not using previous UL BF; drop it if it still + * exits on our end: + */ + if ((ul_tbf = ms_ul_tbf(ms))) { + /* Get rid of previous finished UL TBF before providing a new one */ + LOGPTBFUL(ul_tbf, LOGL_NOTICE, + "Got PACKET RESOURCE REQ while TBF not finished, killing pending UL TBF\n"); + tbf_free(ul_tbf); ul_tbf = NULL; - break; - default: - OSMO_ASSERT(0); } - - /* Here ul_tbf is NULL: - * - SBA case: no previous TBF) and in - * - POLL case: PktResReq is a final ACk confirmation and ul_tbf was freed + /* Similarly, it is for sure not using any DL-TBF. We still may have some because + * we were trying to assign a DL-TBF over CCCH when the MS proactively requested + * for a UL-TBF. In that case we'll need to re-assigna new DL-TBF through PACCH when + * contention resolution is done: */ - - if (request->Exist_MS_Radio_Access_capability2) { - uint8_t ms_class, egprs_ms_class; - ms_class = get_ms_class_by_capability(&request->MS_Radio_Access_capability2); - egprs_ms_class = get_egprs_ms_class_by_capability(&request->MS_Radio_Access_capability2); - if (ms_class) - ms_set_ms_class(ms, ms_class); - if (egprs_ms_class) - ms_set_egprs_ms_class(ms, egprs_ms_class); + if ((dl_tbf = ms_dl_tbf(ms))) { + LOGPTBFDL(dl_tbf, LOGL_NOTICE, + "Got PACKET RESOURCE REQ while DL-TBF pending, killing it\n"); + tbf_free(dl_tbf); + dl_tbf = NULL; } - - ul_tbf = tbf_alloc_ul_pacch(bts(), ms, trx_no()); - if (!ul_tbf) { - handle_tbf_reject(bts(), ms, trx_no(), ts_no); + break; + case PDCH_ULC_NODE_TBF_POLL: + if (item->tbf_poll.poll_tbf->direction != GPRS_RLCMAC_UL_TBF) { + LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " + "Unexpectedly received for DL TBF %s\n", fn, + tbf_name(item->tbf_poll.poll_tbf)); + /* let common path expire the poll */ goto return_unref; } - - /* Set control TS to the TS where this PktResReq was received, - * which in practice happens to be the control_ts from the - * previous UL-TBF or SBA. When CTRL ACK is received as RRBP of the Pkt - * UL Ass scheduled below, then TBF_EV_ASSIGN_ACK_PACCH will be - * sent to tbf_fsm which will call tbf_assign_control_ts(), - * effectively setting back control_ts to - * tbf->initial_common_ts. */ - LOGPTBF(ul_tbf, LOGL_DEBUG, "change control TS %d -> %d until assignment is complete.\n", - ul_tbf->control_ts, ts_no); - - ul_tbf->control_ts = ts_no; - /* schedule uplink assignment */ - osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS, NULL); - - /* get measurements */ - get_meas(meas, request); - ms_update_l1_meas(ul_tbf->ms(), meas); -return_unref: - ms_unref(ms); - return; + ul_tbf = tbf_as_ul_tbf(item->tbf_poll.poll_tbf); + if (item->tbf_poll.reason != PDCH_ULC_POLL_UL_ACK) { + LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " + "Unexpectedly received, waiting for poll reason %d\n", + fn, item->tbf_poll.reason); + /* let common path expire the poll */ + goto return_unref; + } + if (tbf_ms(ul_tbf_as_tbf(ul_tbf)) != ms) { + LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "FN=%u PKT RESOURCE REQ: " + "Received from unexpected %s vs exp %s\n", fn, + ms_name_buf(ms, buf, sizeof(buf)), ms_name(tbf_ms(ul_tbf_as_tbf(ul_tbf)))); + /* let common path expire the poll */ + goto return_unref; + } + /* 3GPP TS 44.060 $ 9.3.3.3 */ + LOGPTBFUL(ul_tbf, LOGL_DEBUG, "FN=%u PKT RESOURCE REQ: " + "MS requests reuse of finished UL TBF in RRBP " + "block of final UL ACK/NACK\n", fn); + ul_tbf->n_reset(N3103); + pdch_ulc_release_node(ulc, item); + rc = osmo_fsm_inst_dispatch(ul_tbf->state_fi, TBF_EV_FINAL_UL_ACK_CONFIRMED, (void*)true); + if (rc) { + /* FSM failed handling, get rid of previous finished UL TBF before providing a new one */ + LOGPTBFUL(ul_tbf, LOGL_NOTICE, + "Got PACKET RESOURCE REQ while TBF not finished, killing pending UL TBF\n"); + tbf_free(ul_tbf); + } /* else: ul_tbf has been freed by state_fsm */ + ul_tbf = NULL; + break; + default: + OSMO_ASSERT(0); } - if (request->ID.u.Global_TFI.UnionType) { - struct gprs_rlcmac_dl_tbf *dl_tbf; - int8_t tfi = request->ID.u.Global_TFI.u.DOWNLINK_TFI; - dl_tbf = bts_dl_tbf_by_tfi(bts(), tfi, trx_no(), ts_no); - if (!dl_tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESOURCE REQ unknown downlink TFI=%d\n", tfi); - return; - } - LOGPTBFDL(dl_tbf, LOGL_ERROR, - "RX: [PCU <- BTS] FIXME: Packet resource request\n"); + /* Here ul_tbf is NULL: + * - USF case: Previous TBF is explicitly freed (FIXME: this is incorrect, old TBF should be kept in this case) + * - SBA case: no previous TBF + * - POLL case: PktResReq is a final ACk confirmation and ul_tbf was freed + */ - /* Reset N3101 counter: */ - dl_tbf->n_reset(N3101); - } else { - struct gprs_rlcmac_ul_tbf *ul_tbf; - int8_t tfi = request->ID.u.Global_TFI.u.UPLINK_TFI; - ul_tbf = bts_ul_tbf_by_tfi(bts(), tfi, trx_no(), ts_no); - if (!ul_tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESOURCE REQ unknown uplink TFI=%d\n", tfi); - return; - } - LOGPTBFUL(ul_tbf, LOGL_ERROR, - "RX: [PCU <- BTS] FIXME: Packet resource request\n"); + if (request->Exist_MS_Radio_Access_capability2) { + uint8_t ms_class, egprs_ms_class; + ms_class = get_ms_class_by_capability(&request->MS_Radio_Access_capability2); + egprs_ms_class = get_egprs_ms_class_by_capability(&request->MS_Radio_Access_capability2); + if (ms_class) + ms_set_ms_class(ms, ms_class); + if (egprs_ms_class) + ms_set_egprs_ms_class(ms, egprs_ms_class); + } + + /* get measurements */ + get_meas(meas, request); + ms_update_l1_meas(ms, meas); - /* Reset N3101 counter: */ - ul_tbf->n_reset(N3101); + new_ul_tbf = ms_new_ul_tbf_assigned_pacch(ms, trx_no()); + if (!new_ul_tbf) { + ms_new_ul_tbf_rejected_pacch(ms, this); + goto return_unref; } + + /* Set control TS to the TS where this PktResReq was received, + * which in practice happens to be the control_ts from the + * previous UL-TBF or SBA. When CTRL ACK is received as RRBP of the Pkt + * UL Ass scheduled below, then TBF_EV_ASSIGN_ACK_PACCH will be + * sent to tbf_fsm which will call tbf_assign_control_ts(), + * effectively setting back control_ts to tbf->initial_common_ts. + */ + LOGPTBF(new_ul_tbf, LOGL_INFO, "Change control TS %s -> %s until assignment is complete.\n", + new_ul_tbf->control_ts ? pdch_name_buf(new_ul_tbf->control_ts, buf, sizeof(buf)) : "(none)", + pdch_name(this)); + + new_ul_tbf->control_ts = this; + /* schedule uplink assignment */ + osmo_fsm_inst_dispatch(new_ul_tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS, NULL); +return_unref: + ms_unref(ms, __func__); + return; } void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *report, uint32_t fn) @@ -769,13 +832,16 @@ void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *repor struct gprs_rlcmac_sba *sba; struct pdch_ulc_node *poll; GprsMs *ms; + bool ms_allocated = false; - ms = bts_ms_by_tlli(bts(), report->TLLI, GSM_RESERVED_TMSI); + ms = bts_get_ms_by_tlli(bts(), report->TLLI, GSM_RESERVED_TMSI); if (!ms) { LOGPDCH(this, DRLCMAC, LOGL_NOTICE, "MS send measurement " "but TLLI 0x%08x is unknown\n", report->TLLI); - ms = bts_alloc_ms(bts(), 0, 0); + ms = ms_alloc(bts(), __func__); ms_set_tlli(ms, report->TLLI); + /* Track that we need to free ref at the end: */ + ms_allocated = true; } if ((poll = pdch_ulc_get_node(ulc, fn))) { switch (poll->type) { @@ -796,6 +862,8 @@ void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *repor } } gprs_rlcmac_meas_rep(ms, report); + if (ms_allocated) + ms_unref(ms, __func__); } void gprs_rlcmac_pdch::rcv_cell_change_notification(Packet_Cell_Change_Notification_t *notif, @@ -896,9 +964,6 @@ free_ret: int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn, struct pcu_l1_meas *meas) { - /* First of all, update TDMA clock: */ - bts_set_current_frame_number(trx->bts, fn); - /* No successfully decoded UL block was received during this FN: */ if (len == 0) return 0; @@ -1056,12 +1121,12 @@ gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi( gprs_rlcmac_ul_tbf *gprs_rlcmac_pdch::ul_tbf_by_tfi(uint8_t tfi) { - return as_ul_tbf(tbf_by_tfi(tfi, GPRS_RLCMAC_UL_TBF)); + return tbf_as_ul_tbf(tbf_by_tfi(tfi, GPRS_RLCMAC_UL_TBF)); } gprs_rlcmac_dl_tbf *gprs_rlcmac_pdch::dl_tbf_by_tfi(uint8_t tfi) { - return as_dl_tbf(tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF)); + return tbf_as_dl_tbf(tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF)); } /* lookup TBF Entity (by TFI) */ @@ -1116,7 +1181,7 @@ void gprs_rlcmac_pdch::attach_tbf(gprs_rlcmac_tbf *tbf) num_tbfs_update(tbf, true); if (tbf->direction == GPRS_RLCMAC_UL_TBF) { - ul_tbf = as_ul_tbf(tbf); + ul_tbf = tbf_as_ul_tbf(tbf); m_assigned_usf |= 1 << ul_tbf->m_usf[ts_no]; } m_assigned_tfi[tbf->direction] |= 1UL << tbf->tfi(); @@ -1132,6 +1197,11 @@ void gprs_rlcmac_pdch::detach_tbf(gprs_rlcmac_tbf *tbf) { gprs_rlcmac_ul_tbf *ul_tbf; + LOGPDCH(this, DRLCMAC, LOGL_INFO, "Detaching %s, %d TBFs, " + "USFs = %02x, TFIs = %08x.\n", + tbf->name(), num_tbfs(tbf->direction), + m_assigned_usf, m_assigned_tfi[tbf->direction]); + if (tbf->is_egprs_enabled()) { OSMO_ASSERT(m_num_tbfs_egprs[tbf->direction] > 0); } else { @@ -1140,18 +1210,13 @@ void gprs_rlcmac_pdch::detach_tbf(gprs_rlcmac_tbf *tbf) num_tbfs_update(tbf, false); if (tbf->direction == GPRS_RLCMAC_UL_TBF) { - ul_tbf = as_ul_tbf(tbf); + ul_tbf = tbf_as_ul_tbf(tbf); m_assigned_usf &= ~(1 << ul_tbf->m_usf[ts_no]); } m_assigned_tfi[tbf->direction] &= ~(1UL << tbf->tfi()); m_tbfs[tbf->direction][tbf->tfi()] = NULL; pdch_ulc_release_tbf(ulc, tbf); - - LOGPDCH(this, DRLCMAC, LOGL_INFO, "Detaching %s, %d TBFs, " - "USFs = %02x, TFIs = %08x.\n", - tbf->name(), num_tbfs(tbf->direction), - m_assigned_usf, m_assigned_tfi[tbf->direction]); } bool gprs_rlcmac_pdch::has_gprs_only_tbf_attached() const @@ -1228,8 +1293,8 @@ void pdch_free_all_tbf(struct gprs_rlcmac_pdch *pdch) * PDCH, since they have no TFI assigned (see handle_tbf_reject()). * Get rid of them too: */ llist_for_each_entry_safe(pos, pos2, &pdch->trx->ul_tbfs, list) { - struct gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf((struct gprs_rlcmac_tbf *)pos->entry); - if (ul_tbf->control_ts == pdch->ts_no) + struct gprs_rlcmac_ul_tbf *ul_tbf = tbf_as_ul_tbf((struct gprs_rlcmac_tbf *)pos->entry); + if (ul_tbf->control_ts == pdch) tbf_free(ul_tbf); } } @@ -1243,3 +1308,27 @@ bool pdch_is_enabled(const struct gprs_rlcmac_pdch *pdch) { return pdch->is_enabled(); } + +/* To be called only on enabled PDCHs. Used to gather information on whether the + * PDCH is currently unable to allocate more TBFs due to any resource being + * full. Used by bts_all_pdch_allocated() for counting purposes. */ +bool pdch_is_full(const struct gprs_rlcmac_pdch *pdch) +{ + return pdch->assigned_tfi(GPRS_RLCMAC_UL_TBF) == NO_FREE_TFI || + pdch->assigned_tfi(GPRS_RLCMAC_DL_TBF) == NO_FREE_TFI || + find_free_usf(pdch->assigned_usf()) < 0; +} + +const char *pdch_name(const struct gprs_rlcmac_pdch *pdch) +{ + static char _pdch_name_buf[128]; + return pdch_name_buf(pdch, _pdch_name_buf, sizeof(_pdch_name_buf)); +} + +char *pdch_name_buf(const struct gprs_rlcmac_pdch *pdch, char *buf, size_t buf_size) +{ + struct osmo_strbuf sb = { .buf = buf, .len = buf_size }; + OSMO_STRBUF_PRINTF(sb, "PDCH(bts=%" PRIu8 ",trx=%" PRIu8 ",ts=%" PRIu8 ")", + pdch->trx->bts->nr, pdch->trx->trx_no, pdch->ts_no); + return buf; +} |