diff options
Diffstat (limited to 'src/tbf_ul_ack_fsm.c')
-rw-r--r-- | src/tbf_ul_ack_fsm.c | 100 |
1 files changed, 61 insertions, 39 deletions
diff --git a/src/tbf_ul_ack_fsm.c b/src/tbf_ul_ack_fsm.c index 32e3533f..2fa20d70 100644 --- a/src/tbf_ul_ack_fsm.c +++ b/src/tbf_ul_ack_fsm.c @@ -12,10 +12,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 <unistd.h> @@ -37,13 +33,13 @@ #define X(s) (1 << (s)) -const struct osmo_tdef_state_timeout tbf_ul_ack_fsm_timeouts[32] = { +static const struct osmo_tdef_state_timeout tbf_ul_ack_fsm_timeouts[32] = { [TBF_UL_ACK_ST_NONE] = {}, [TBF_UL_ACK_ST_SCHED_UL_ACK] = {}, [TBF_UL_ACK_ST_WAIT_ACK] = {}, }; -const struct value_string tbf_ul_ack_fsm_event_names[] = { +static const struct value_string tbf_ul_ack_fsm_event_names[] = { { TBF_UL_ACK_EV_SCHED_ACK, "SCHED_ACK" }, { TBF_UL_ACK_EV_CREATE_RLCMAC_MSG, "CREATE_RLCMAC_MSG" }, { TBF_UL_ACK_EV_RX_CTRL_ACK, "RX_CTRL_ACK" }, @@ -51,6 +47,15 @@ const struct value_string tbf_ul_ack_fsm_event_names[] = { { 0, NULL } }; +/* Transition to a state, using the T timer defined in tbf_ul_ack_fsm_timeouts. + * The actual timeout value is in turn obtained from conn->T_defs. + * Assumes local variable fi exists. */ +#define tbf_ul_ack_fsm_state_chg(fi, NEXT_STATE) \ + osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, \ + tbf_ul_ack_fsm_timeouts, \ + the_pcu->T_defs, \ + -1) + static struct msgb *create_ul_ack_nack(const struct tbf_ul_ack_fsm_ctx *ctx, const struct tbf_ul_ack_ev_create_rlcmac_msg_ctx *d, bool final) @@ -59,11 +64,10 @@ static struct msgb *create_ul_ack_nack(const struct tbf_ul_ack_fsm_ctx *ctx, int rc; unsigned int rrbp = 0; uint32_t new_poll_fn = 0; - struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)ctx->tbf; - struct GprsMs *ms = tbf_ms(tbf); + struct gprs_rlcmac_tbf *tbf = ul_tbf_as_tbf(ctx->tbf); if (final) { - rc = tbf_check_polling(tbf, d->fn, d->ts, &new_poll_fn, &rrbp); + rc = tbf_check_polling(tbf, d->pdch, d->fn, &new_poll_fn, &rrbp); if (rc < 0) return NULL; } @@ -81,21 +85,11 @@ static struct msgb *create_ul_ack_nack(const struct tbf_ul_ack_fsm_ctx *ctx, bitvec_pack(ack_vec, msgb_put(msg, 23)); bitvec_free(ack_vec); - /* TS 44.060 7a.2.1.1: "The contention resolution is completed on - * the network side when the network receives an RLC data block that - * comprises the TLLI value that identifies the mobile station and the - * TFI value associated with the TBF." - * However, it's handier for us to mark contention resolution success - * here since according to spec upon rx UL ACK is the time at which MS - * realizes contention resolution succeeds. */ - if (ms_tlli(ms) != GSM_RESERVED_TMSI) - ul_tbf_contention_resolution_success(ctx->tbf); - if (final) { - tbf_set_polling(tbf, new_poll_fn, d->ts, PDCH_ULC_POLL_UL_ACK); - LOGPTBFUL(tbf, LOGL_DEBUG, - "Scheduled UL Acknowledgement polling on PACCH (FN=%d, TS=%d)\n", - new_poll_fn, d->ts); + tbf_set_polling(tbf, d->pdch, new_poll_fn, PDCH_ULC_POLL_UL_ACK); + LOGPTBFUL(ctx->tbf, LOGL_DEBUG, + "Scheduled UL Acknowledgement polling on PACCH (FN=%d, TS=%d)\n", + new_poll_fn, d->pdch->ts_no); } return msg; @@ -115,7 +109,8 @@ static void st_none(struct osmo_fsm_inst *fi, uint32_t event, void *data) static void st_sched_ul_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct tbf_ul_ack_fsm_ctx *ctx = (struct tbf_ul_ack_fsm_ctx *)fi->priv; - struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)ctx->tbf; + struct gprs_rlcmac_ul_tbf *tbf = ctx->tbf; + struct GprsMs *ms = tbf_ms(ul_tbf_as_tbf(tbf)); struct tbf_ul_ack_ev_create_rlcmac_msg_ctx *data_ctx; bool final; @@ -126,7 +121,7 @@ static void st_sched_ul_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data break; case TBF_UL_ACK_EV_CREATE_RLCMAC_MSG: data_ctx = (struct tbf_ul_ack_ev_create_rlcmac_msg_ctx *)data; - final = tbf_state(tbf) == TBF_ST_FINISHED; + final = tbf_state(ul_tbf_as_tbf(tbf)) == TBF_ST_FINISHED; data_ctx->msg = create_ul_ack_nack(ctx, data_ctx, final); if (!data_ctx->msg) return; @@ -134,6 +129,28 @@ static void st_sched_ul_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_WAIT_ACK); else tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_NONE); + + /* TS 44.060 7a.2.1.1: "The contention resolution is completed on + * the network side when the network receives an RLC data block that + * comprises the TLLI value that identifies the mobile station and the + * TFI value associated with the TBF." (see TBF_EV_FIRST_UL_DATA_RECVD). + * + * However, it's handier for us to mark contention resolution success here + * since upon rx UL ACK is the time at which MS realizes contention resolution + * succeeds: + * TS 44.060 7.1.2.3: "The contention resolution is successfully completed + * on the mobile station side when the mobile station receives a + * PACKET UPLINK ACK/NACK" + * + * This event must be triggered here *after* potentially transitioning + * to ST_WAIT_ACK above, so that gprs_ms knows whether it can create a + * DL TBF on PACCH of the UL_TBF or not (not possible if we are in + * ST_WAIT_ACK, since UL TBF is terminating sending the final PKT CTRL + * ACK). + */ + if (ms_tlli(ms) != GSM_RESERVED_TMSI && !ul_tbf_contention_resolution_done(ctx->tbf)) + osmo_fsm_inst_dispatch(tbf_state_fi(ul_tbf_as_tbf(ctx->tbf)), TBF_EV_CONTENTION_RESOLUTION_MS_SUCCESS, NULL); + break; default: OSMO_ASSERT(0); @@ -143,7 +160,7 @@ static void st_sched_ul_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data static void st_wait_ctrl_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct tbf_ul_ack_fsm_ctx *ctx = (struct tbf_ul_ack_fsm_ctx *)fi->priv; - struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)ctx->tbf; + struct gprs_rlcmac_ul_tbf *tbf = ctx->tbf; switch (event) { case TBF_UL_ACK_EV_SCHED_ACK: @@ -153,9 +170,9 @@ static void st_wait_ctrl_ack(struct osmo_fsm_inst *fi, uint32_t event, void *dat tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_NONE); break; case TBF_UL_ACK_EV_POLL_TIMEOUT: - LOGPTBF(tbf, LOGL_NOTICE, + LOGPTBFUL(tbf, LOGL_NOTICE, "Timeout for polling PACKET CONTROL ACK for PACKET UPLINK ACK: %s\n", - tbf_rlcmac_diag(tbf)); + tbf_rlcmac_diag(ul_tbf_as_tbf(tbf))); /* Reschedule Ul Ack/NAck */ tbf_ul_ack_fsm_state_chg(fi, TBF_UL_ACK_ST_SCHED_UL_ACK); break; @@ -220,39 +237,44 @@ static __attribute__((constructor)) void tbf_ul_ack_fsm_init(void) } -struct msgb *tbf_ul_ack_create_rlcmac_msg(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts) +struct msgb *tbf_ul_ack_create_rlcmac_msg(const struct gprs_rlcmac_ul_tbf *ul_tbf, + const struct gprs_rlcmac_pdch *pdch, + uint32_t fn) { int rc; struct tbf_ul_ack_ev_create_rlcmac_msg_ctx data_ctx = { + .pdch = pdch, .fn = fn, - .ts = ts, .msg = NULL, }; - OSMO_ASSERT(tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF); - rc = osmo_fsm_inst_dispatch(tbf_ul_ack_fi((const struct gprs_rlcmac_ul_tbf *)tbf), TBF_UL_ACK_EV_CREATE_RLCMAC_MSG, &data_ctx); + rc = osmo_fsm_inst_dispatch(tbf_ul_ack_fi(ul_tbf), TBF_UL_ACK_EV_CREATE_RLCMAC_MSG, &data_ctx); if (rc != 0 || !data_ctx.msg) return NULL; return data_ctx.msg; } -bool tbf_ul_ack_rts(const struct gprs_rlcmac_tbf *tbf) +bool tbf_ul_ack_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct gprs_rlcmac_pdch *pdch) { - struct osmo_fsm_inst *fi = tbf_ul_ack_fi((const struct gprs_rlcmac_ul_tbf *)tbf); + struct osmo_fsm_inst *fi; + + if (!tbf_is_control_ts(ul_tbf_as_tbf_const(ul_tbf), pdch)) + return false; + + fi = tbf_ul_ack_fi(ul_tbf); return fi->state == TBF_UL_ACK_ST_SCHED_UL_ACK; } /* Did we already send the Final ACK and we are waiting for its confirmation (CTRL ACK) ? */ -bool tbf_ul_ack_waiting_cnf_final_ack(const struct gprs_rlcmac_tbf* tbf) +bool tbf_ul_ack_waiting_cnf_final_ack(const struct gprs_rlcmac_ul_tbf *ul_tbf) { - OSMO_ASSERT(tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF); - struct osmo_fsm_inst *fi = tbf_ul_ack_fi((const struct gprs_rlcmac_ul_tbf *)tbf); + struct osmo_fsm_inst *fi = tbf_ul_ack_fi(ul_tbf); return fi->state == TBF_UL_ACK_ST_WAIT_ACK; } -bool tbf_ul_ack_exp_ctrl_ack(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts) +bool tbf_ul_ack_exp_ctrl_ack(const struct gprs_rlcmac_ul_tbf *ul_tbf, uint32_t fn, uint8_t ts) { - struct osmo_fsm_inst *fi = tbf_ul_ack_fi((const struct gprs_rlcmac_ul_tbf *)tbf); + struct osmo_fsm_inst *fi = tbf_ul_ack_fi(ul_tbf); return fi->state == TBF_UL_ACK_ST_WAIT_ACK; /* FIXME: validate FN and TS match: && ctx->poll_fn = fn && ctx->poll_ts == ts */ } |