diff options
author | Pau Espin Pedrol <pespin@espeweb.net> | 2021-02-01 14:52:48 +0100 |
---|---|---|
committer | laforge <laforge@osmocom.org> | 2021-02-03 08:34:04 +0000 |
commit | 952cb3d5d7e07c3e22aac080a3d3ddc7925093c3 (patch) | |
tree | e241a4ac3ad54109f8881350fe093217182ed4bb /src | |
parent | a58ec615147e34a3860bdf92e067943499d21300 (diff) |
nacc: Implement Pkt Cell Change Continue retransmission
Use the fact that the MS must answer the RRBP of the Pkt Cell Change
Continue with a CTRL ACK to find out whether the message was received
successfuly or a retransmission is potentially required.
3GPP TS 44.060:
"""
When the mobile station receives the PACKET CELL CHANGE ORDER or
the PACKET CELL CHANGE CONTINUE message the mobile station shall
transmit a PACKET CONTROL ACKNOWLEDGMENT message in the specified
uplink radio block if a valid RRBP field is received as part of the
message; the mobile station may then switch to a new cell.
"""
Related: SYS#4909
Change-Id: I7cc28922e71699598da0ef6eb90136a47d3c002f
Diffstat (limited to 'src')
-rw-r--r-- | src/encoding.cpp | 10 | ||||
-rw-r--r-- | src/encoding.h | 6 | ||||
-rw-r--r-- | src/gprs_ms.c | 10 | ||||
-rw-r--r-- | src/gprs_ms.h | 2 | ||||
-rw-r--r-- | src/gprs_rlcmac_sched.cpp | 2 | ||||
-rw-r--r-- | src/nacc_fsm.c | 48 | ||||
-rw-r--r-- | src/nacc_fsm.h | 7 | ||||
-rw-r--r-- | src/pdch.cpp | 14 | ||||
-rw-r--r-- | src/tbf.cpp | 20 | ||||
-rw-r--r-- | src/tbf.h | 3 |
10 files changed, 105 insertions, 17 deletions
diff --git a/src/encoding.cpp b/src/encoding.cpp index 38bc175d..8bc8d15b 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -1757,14 +1757,14 @@ void write_packet_neighbour_cell_data(RlcMacDownlink_t *block, block->u.Packet_Neighbour_Cell_Data.Container = *container; } -void write_packet_cell_change_continue(RlcMacDownlink_t *block, - bool tfi_is_dl, uint8_t tfi, bool exist_id, - uint16_t arfcn, uint8_t bsic, uint8_t container_id) +void write_packet_cell_change_continue(RlcMacDownlink_t *block, uint8_t poll, uint8_t rrbp, + bool tfi_is_dl, uint8_t tfi, bool exist_id, + uint16_t arfcn, uint8_t bsic, uint8_t container_id) { block->PAYLOAD_TYPE = 0x1; // RLC/MAC control block that does not include the optional octets of the RLC/MAC control header - block->RRBP = 0; // 0: N+13 - block->SP = 0; // RRBP field is not valid + block->RRBP = rrbp; // RRBP (e.g. N+13) + block->SP = poll; // RRBP field is valid? block->USF = 0x0; // Uplink state flag block->u.Packet_Cell_Change_Continue.MESSAGE_TYPE = MT_PACKET_CELL_CHANGE_CONTINUE; diff --git a/src/encoding.h b/src/encoding.h index 4ebfa35f..89d057cf 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -124,9 +124,9 @@ void write_packet_neighbour_cell_data(RlcMacDownlink_t *block, bool tfi_is_dl, uint8_t tfi, uint8_t container_id, uint8_t container_idx, PNCDContainer_t *container); -void write_packet_cell_change_continue(RlcMacDownlink_t *block, - bool tfi_is_dl, uint8_t tfi, bool exist_id, - uint16_t arfcn, uint8_t bsic, uint8_t container_id); +void write_packet_cell_change_continue(RlcMacDownlink_t *block, uint8_t poll, uint8_t rrbp, + bool tfi_is_dl, uint8_t tfi, bool exist_id, + uint16_t arfcn, uint8_t bsic, uint8_t container_id); #ifdef __cplusplus } diff --git a/src/gprs_ms.c b/src/gprs_ms.c index 8078b108..ab1a0678 100644 --- a/src/gprs_ms.c +++ b/src/gprs_ms.c @@ -958,13 +958,17 @@ bool ms_nacc_rts(const struct GprsMs *ms) return false; } -struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf) +struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts) { int rc; struct nacc_ev_create_rlcmac_msg_ctx data_ctx; - data_ctx.tbf = tbf; - data_ctx.msg = NULL; + data_ctx = (struct nacc_ev_create_rlcmac_msg_ctx) { + .tbf = tbf, + .fn = fn, + .ts = ts, + .msg = NULL, + }; rc = osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_CREATE_RLCMAC_MSG, &data_ctx); if (rc != 0 || !data_ctx.msg) diff --git a/src/gprs_ms.h b/src/gprs_ms.h index c57bbf6a..6674261a 100644 --- a/src/gprs_ms.h +++ b/src/gprs_ms.h @@ -144,7 +144,7 @@ void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb); int ms_nacc_start(struct GprsMs *ms, Packet_Cell_Change_Notification_t *notif); bool ms_nacc_rts(const struct GprsMs *ms); -struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf); +struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts); static inline bool ms_is_idle(const struct GprsMs *ms) { diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index a8f65dee..5f029a0a 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -203,7 +203,7 @@ static struct msgb *sched_select_ctrl_msg( else if (tbf == tbfs->ul_ack) msg = tbfs->ul_ack->create_ul_ack(fn, ts); else if (tbf == tbfs->nacc) { - msg = ms_nacc_create_rlcmac_msg(tbf->ms(), tbf); + msg = ms_nacc_create_rlcmac_msg(tbf->ms(), tbf, fn, ts); } if (!msg) { diff --git a/src/nacc_fsm.c b/src/nacc_fsm.c index d160404e..b479f9c6 100644 --- a/src/nacc_fsm.c +++ b/src/nacc_fsm.c @@ -46,6 +46,7 @@ static const struct osmo_tdef_state_timeout nacc_fsm_timeouts[32] = { [NACC_ST_WAIT_REQUEST_SI] = { .T = PCU_TDEF_SI_RESOLVE_TO }, [NACC_ST_TX_NEIGHBOUR_DATA] = {}, [NACC_ST_TX_CELL_CHG_CONTINUE] = {}, + [NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK] = {}, /* Timeout through event controlled by tbf::poll_timeout() */ [NACC_ST_DONE] = {}, }; @@ -64,6 +65,8 @@ const struct value_string nacc_fsm_event_names[] = { { NACC_EV_RX_RAC_CI, "RX_RAC_CI" }, { NACC_EV_RX_SI, "RX_SI" }, { NACC_EV_CREATE_RLCMAC_MSG, "CREATE_RLCMAC_MSG" }, + { NACC_EV_RX_CELL_CHG_CONTINUE_ACK, "RX_CELL_CHG_CONTINUE_ACK"}, + { NACC_EV_TIMEOUT_CELL_CHG_CONTINUE, "TIMEOUT_CELL_CHG_CONTINUE" }, { 0, NULL } }; @@ -156,12 +159,21 @@ free_ret: /* TS 44 060 11.2.2a Packet Cell Change Continue */ static struct msgb *create_packet_cell_chg_continue(const struct nacc_fsm_ctx *ctx, - const struct gprs_rlcmac_tbf *tbf) + const struct nacc_ev_create_rlcmac_msg_ctx *data, + uint32_t *new_poll_fn) { struct msgb *msg; int rc; RlcMacDownlink_t *mac_control_block; + struct gprs_rlcmac_tbf *tbf = data->tbf; struct GprsMs *ms = tbf_ms(tbf); + unsigned int rrbp; + + rc = tbf_check_polling(tbf, data->fn, data->ts, new_poll_fn, &rrbp); + if (rc < 0) { + LOGP(DTBF, LOGL_ERROR, "Failed registering poll for Pkt Cell Chg Continue (%d)\n", rc); + return NULL; + } msg = msgb_alloc(GSM_MACBLOCK_LEN, "pkt_cell_chg_continue"); if (!msg) @@ -180,7 +192,7 @@ static struct msgb *create_packet_cell_chg_continue(const struct nacc_fsm_ctx *c uint8_t tfi_is_dl = tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF; uint8_t tfi = tbf_tfi(tbf); uint8_t container_id = 0; - write_packet_cell_change_continue(mac_control_block, tfi_is_dl, tfi, true, + write_packet_cell_change_continue(mac_control_block, 1, rrbp, tfi_is_dl, tfi, true, ctx->neigh_key.tgt_arfcn, ctx->neigh_key.tgt_bsic, container_id); LOGP(DNACC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Cell Change Continue +++++++++++++++++++++++++\n"); rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block); @@ -191,6 +203,7 @@ static struct msgb *create_packet_cell_chg_continue(const struct nacc_fsm_ctx *c LOGP(DNACC, LOGL_DEBUG, "------------------------- TX : Packet Cell Change Continue -------------------------\n"); rate_ctr_inc(&bts_rate_counters(ms->bts)->ctr[CTR_PKT_CELL_CHG_CONTINUE]); talloc_free(mac_control_block); + tbf_set_polling(tbf, *new_poll_fn, data->ts, GPRS_RLCMAC_POLL_CELL_CHG_CONTINUE); return msg; free_ret: @@ -458,7 +471,24 @@ static void st_cell_chg_continue(struct osmo_fsm_inst *fi, uint32_t event, void switch (event) { case NACC_EV_CREATE_RLCMAC_MSG: data_ctx = (struct nacc_ev_create_rlcmac_msg_ctx *)data; - data_ctx->msg = create_packet_cell_chg_continue(ctx, data_ctx->tbf); + data_ctx->msg = create_packet_cell_chg_continue(ctx, data_ctx, &ctx->continue_poll_fn); + if (data_ctx->msg) { + ctx->continue_poll_ts = data_ctx->ts; + nacc_fsm_state_chg(fi, NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK); + } + break; + default: + OSMO_ASSERT(0); + } +} + +static void st_wait_cell_chg_continue_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case NACC_EV_TIMEOUT_CELL_CHG_CONTINUE: + nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE); + break; + case NACC_EV_RX_CELL_CHG_CONTINUE_ACK: nacc_fsm_state_chg(fi, NACC_ST_DONE); break; default: @@ -543,10 +573,20 @@ static struct osmo_fsm_state nacc_fsm_states[] = { X(NACC_EV_RX_SI) | X(NACC_EV_CREATE_RLCMAC_MSG), .out_state_mask = - X(NACC_ST_DONE), + X(NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK), .name = "TX_CELL_CHG_CONTINUE", .action = st_cell_chg_continue, }, + [NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK] = { + .in_event_mask = + X(NACC_EV_RX_CELL_CHG_CONTINUE_ACK) | + X(NACC_EV_TIMEOUT_CELL_CHG_CONTINUE), + .out_state_mask = + X(NACC_ST_TX_CELL_CHG_CONTINUE) | + X(NACC_ST_DONE), + .name = "WAIT_CELL_CHG_CONTINUE_ACK", + .action = st_wait_cell_chg_continue_ack, + }, [NACC_ST_DONE] = { .in_event_mask = 0, .out_state_mask = 0, diff --git a/src/nacc_fsm.h b/src/nacc_fsm.h index 9107dafd..7b0adfd0 100644 --- a/src/nacc_fsm.h +++ b/src/nacc_fsm.h @@ -32,6 +32,8 @@ enum nacc_fsm_event { NACC_EV_RX_RAC_CI, /* no data passed, RAC_CI became available in neigh_cache */ NACC_EV_RX_SI, /* data: struct si_cache_entry* */ NACC_EV_CREATE_RLCMAC_MSG, /* data: struct nacc_ev_create_rlcmac_msg_ctx* */ + NACC_EV_RX_CELL_CHG_CONTINUE_ACK, + NACC_EV_TIMEOUT_CELL_CHG_CONTINUE, /* Poll Timeout */ }; enum nacc_fsm_states { @@ -40,6 +42,7 @@ enum nacc_fsm_states { NACC_ST_WAIT_REQUEST_SI, NACC_ST_TX_NEIGHBOUR_DATA, NACC_ST_TX_CELL_CHG_CONTINUE, + NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK, NACC_ST_DONE, }; @@ -53,11 +56,15 @@ struct nacc_fsm_ctx { struct si_cache_value si_info; /* SI info resolved from SGSN, to be sent to MS */ size_t si_info_bytes_sent; /* How many bytes out of si_info->si_len were already sent to MS */ size_t container_idx; /* Next container_idx to assign when sending Packet Neighbor Data message */ + uint32_t continue_poll_fn; /* Scheduled poll FN to CTRL ACK the Pkt Cell Chg Continue */ + uint8_t continue_poll_ts; /* Scheduled poll TS to CTRL ACK the Pkt Cell Chg Continue */ }; /* passed as data in NACC_EV_CREATE_RLCMAC_MSG */ struct nacc_ev_create_rlcmac_msg_ctx { struct gprs_rlcmac_tbf *tbf; /* target tbf to create messages for */ + uint32_t fn; /* FN where the created DL ctrl block is to be sent */ + uint8_t ts; /* TS where the created DL ctrl block is to be sent */ struct msgb *msg; /* to be filled by FSM during event processing */ }; diff --git a/src/pdch.cpp b/src/pdch.cpp index 2028ba20..787208c2 100644 --- a/src/pdch.cpp +++ b/src/pdch.cpp @@ -47,6 +47,7 @@ extern "C" { #include "coding_scheme.h" #include "gsm_rlcmac.h" +#include "nacc_fsm.h" } #include <errno.h> @@ -394,6 +395,19 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, return; } + if (ms->nacc && ms->nacc->fi->state == NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK && + ms->nacc->continue_poll_fn == fn && ms->nacc->continue_poll_ts == ts_no) { + osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_RX_CELL_CHG_CONTINUE_ACK, NULL); + /* Don't assume MS is no longer reachable (hence don't free) after this: TS 44.060 + * "When the mobile station receives the PACKET CELL CHANGE ORDER + * or the PACKET CELL CHANGE CONTINUE message the mobile station + * shall transmit a PACKET CONTROL ACKNOWLEDGMENT message in the + * specified uplink radio block if a valid RRBP field is + * received as part of the message; the mobile station _MAY_ then + * switch to a new cell." + */ + return; + } LOGP(DRLCMAC, LOGL_ERROR, "Error: received PACET CONTROL ACK " "at no request\n"); } diff --git a/src/tbf.cpp b/src/tbf.cpp index 35bd81d0..7caa2cea 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -49,6 +49,7 @@ extern "C" { #include "gsm_rlcmac.h" #include "coding_scheme.h" +#include "nacc_fsm.h" } #include <errno.h> @@ -614,6 +615,10 @@ void gprs_rlcmac_tbf::set_polling(uint32_t new_poll_fn, uint8_t ts, enum gprs_rl LOGPTBFDL(this, LOGL_DEBUG, "Scheduled DL Acknowledgement polling on %s (FN=%d, TS=%d)\n", chan, poll_fn, poll_ts); break; + case GPRS_RLCMAC_POLL_CELL_CHG_CONTINUE: + LOGPTBFDL(this, LOGL_DEBUG, "Scheduled 'Packet Cell Change Continue' polling on %s (FN=%d, TS=%d)\n", + chan, poll_fn, poll_ts); + break; } } @@ -690,6 +695,11 @@ void gprs_rlcmac_tbf::poll_timeout() } /* reschedule DL assignment */ dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS; + } else if (m_ms->nacc && m_ms->nacc->fi->state == NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK && + m_ms->nacc->continue_poll_fn == poll_fn && m_ms->nacc->continue_poll_ts == poll_ts) { + /* Timeout waiting for CTRL ACK acking Pkt Cell Change Continue */ + osmo_fsm_inst_dispatch(m_ms->nacc->fi, NACC_EV_TIMEOUT_CELL_CHG_CONTINUE, NULL); + return; } else if (direction == GPRS_RLCMAC_DL_TBF) { gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this); @@ -1203,3 +1213,13 @@ uint8_t tbf_tfi(const struct gprs_rlcmac_tbf *tbf) { return tbf->tfi(); } + +int tbf_check_polling(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts, uint32_t *poll_fn, unsigned int *rrbp) +{ + return tbf->check_polling(fn, ts, poll_fn, rrbp); +} + +void tbf_set_polling(struct gprs_rlcmac_tbf *tbf, uint32_t new_poll_fn, uint8_t ts, enum gprs_rlcmac_tbf_poll_type t) +{ + return tbf->set_polling(new_poll_fn, ts, t); +} @@ -68,6 +68,7 @@ enum gprs_rlcmac_tbf_poll_type { GPRS_RLCMAC_POLL_DL_ASS, GPRS_RLCMAC_POLL_UL_ACK, GPRS_RLCMAC_POLL_DL_ACK, + GPRS_RLCMAC_POLL_CELL_CHG_CONTINUE, }; enum gprs_rlcmac_tbf_poll_state { @@ -206,6 +207,8 @@ uint8_t tbf_ul_slots(const struct gprs_rlcmac_tbf *tbf); bool tbf_is_tfi_assigned(const struct gprs_rlcmac_tbf *tbf); uint8_t tbf_tfi(const struct gprs_rlcmac_tbf *tbf); int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf); +int tbf_check_polling(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts, uint32_t *poll_fn, unsigned int *rrbp); +void tbf_set_polling(struct gprs_rlcmac_tbf *tbf, uint32_t new_poll_fn, uint8_t ts, enum gprs_rlcmac_tbf_poll_type t); #ifdef __cplusplus } #endif |