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
This commit is contained in:
parent
a58ec61514
commit
952cb3d5d7
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
14
src/pdch.cpp
14
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");
|
||||
}
|
||||
|
|
20
src/tbf.cpp
20
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
|
||||
|
|
Loading…
Reference in New Issue