lchan_fsm: make rsl mode-modify working again
osmo-nitb supports the modification of an lchan if the lchan is compatible but in the wrong mode. This feature was dropped in the transition to AoIP/bsc-split. However, osmo-bsc still has code to generate and parse the messeages, but the FSMs do not support a mode modify yetm Lets add handling for mode-modify to the lchan_fsm and assignment_fsm in order to support mode modify again Change-Id: I2c5a283b1ee33745cc1fcfcc09a0f9382224e2eb Related: OS#4549
This commit is contained in:
parent
7e9ac64ba0
commit
92eed41a99
|
@ -22,6 +22,7 @@ labelloc=t; label="Assignment FSM"
|
|||
bssap -> gscon [label="GSCON_EV_ASSIGNMENT_START\ndata=struct assignment_request",style=dotted]
|
||||
|
||||
gscon -> WAIT_LCHAN_ACTIVE [label="assignment_fsm_start()",style=dotted]
|
||||
gscon -> WAIT_LCHAN_ESTABLISHED [label="assignment_fsm_start()\n(mode modify)",style=dotted]
|
||||
WAIT_LCHAN_ACTIVE -> lchan [label="lchan_activate()\nFOR_ASSIGNMENT",style=dotted]
|
||||
lchan -> WAIT_LCHAN_ACTIVE [label="ASSIGNMENT_EV_\nLCHAN_\nACTIVE,ERROR",style=dotted]
|
||||
lchan -> WAIT_LCHAN_ESTABLISHED [label="ASSIGNMENT_EV_\nLCHAN_\nESTABLISHED,ERROR",style=dotted]
|
||||
|
|
|
@ -9,6 +9,14 @@ msc {
|
|||
gscon note gscon [label="GSCON_EV_ASSIGNMENT_START\n data=struct assignment_request"];
|
||||
gscon abox gscon [label="ST_ASSIGNMENT"];
|
||||
ass <- gscon [label="assignment_fsm_start()"];
|
||||
|||;
|
||||
--- [label="IF current lchan supports requested channel mode (re-use)"];
|
||||
lchan <- ass [label="LCHAN_EV_REQUEST_MODE_MODIFY"];
|
||||
ass abox ass [label="ASSIGNMENT_ST_\nWAIT_LCHAN_ESTABLISHED"];
|
||||
ass rbox ass [label="see below"];
|
||||
|
||||
|||;
|
||||
--- [label="ELSE: if current lchan does not support requested channel mode (establish new lchan)"];
|
||||
ass abox ass [label="ASSIGNMENT_ST_\nWAIT_LCHAN_ACTIVE"];
|
||||
|
||||
|||;
|
||||
|
|
|
@ -38,4 +38,10 @@ labelloc=t; label="lchan FSM"
|
|||
rtp -> WAIT_RLL_RTP_ESTABLISH [label="LCHAN_EV_RTP_READY",style=dotted]
|
||||
rtp -> ESTABLISHED [label="LCHAN_EV_RTP_RELEASED",style=dotted]
|
||||
|
||||
ESTABLISHED -> WAIT_RR_CHAN_MODE_MODIFY_ACK [label="LCHAN_EV_REQUEST_MODE_MODIFY"]
|
||||
WAIT_RR_CHAN_MODE_MODIFY_ACK -> WAIT_RSL_CHAN_MODE_MODIFY_ACK [label="LCHAN_EV_RR_CHAN_MODE_MODIFY_ACK"]
|
||||
WAIT_RSL_CHAN_MODE_MODIFY_ACK -> WAIT_RLL_RTP_ESTABLISH [label="LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK\nwhen adding RTP"]
|
||||
WAIT_RSL_CHAN_MODE_MODIFY_ACK -> ESTABLISHED [label="LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK\nno change to RTP"]
|
||||
WAIT_RR_CHAN_MODE_MODIFY_ACK -> BORKEN [label="error/timeout",style=dashed]
|
||||
WAIT_RSL_CHAN_MODE_MODIFY_ACK -> BORKEN [label="error/timeout",style=dashed]
|
||||
}
|
||||
|
|
|
@ -129,6 +129,26 @@ msc {
|
|||
...;
|
||||
...;
|
||||
|
||||
ms rbox mgwep [label="On Mode Modify (e.g. change a TCH lchan from signalling to voice)"];
|
||||
lchan abox lchan [label="LCHAN_ST_\nWAIT_RR_CHAN_\nMODE_MODIFY_ACK"];
|
||||
ms <= lchan [label="RR Chan Mode Modif"];
|
||||
...;
|
||||
ms => lchan [label="RR Chan Mode Modif Ack"];
|
||||
lchan abox lchan [label="LCHAN_ST_\nWAIT_RSL_CHAN_\nMODE_MODIFY_ACK"];
|
||||
ms <= lchan [label="RSL MT Mode Modify Req"];
|
||||
...;
|
||||
ms => lchan [label="RSL MT Mode Modify Ack"];
|
||||
--- [label="IF adding RTP stream"];
|
||||
lchan abox lchan [label="LCHAN_ST_WAIT_\nRLL_RTP_ESTABLISH\nT3101"];
|
||||
lchan rbox rtp [label="See above at 'LCHAN_RTP_EV_LCHAN_READY'"];
|
||||
--- [label="IF not adding RTP stream"];
|
||||
lchan abox lchan [label="LCHAN_ST_\nESTABLISHED"];
|
||||
--- [label="END: whether adding voice stream"];
|
||||
|
||||
...;
|
||||
...;
|
||||
...;
|
||||
|
||||
ms rbox mgwep [label="When the MS or BTS release the lchan"];
|
||||
lchan abox lchan [label="LCHAN_ST_\nESTABLISHED"];
|
||||
ms -> lchan [label="RLL Release Ind for SAPI=0"];
|
||||
|
|
|
@ -50,6 +50,8 @@ enum bts_counter_id {
|
|||
BTS_CTR_LCHAN_BORKEN_EV_RF_CHAN_REL_ACK,
|
||||
BTS_CTR_LCHAN_BORKEN_EV_VTY,
|
||||
BTS_CTR_LCHAN_BORKEN_EV_TEARDOWN,
|
||||
BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RR_CHAN_MODE_MODIFY_ACK,
|
||||
BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RSL_CHAN_MODE_MODIFY_ACK,
|
||||
BTS_CTR_TS_BORKEN_FROM_NOT_INITIALIZED,
|
||||
BTS_CTR_TS_BORKEN_FROM_UNUSED,
|
||||
BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_ACT,
|
||||
|
@ -136,6 +138,8 @@ static const struct rate_ctr_desc bts_ctr_description[] = {
|
|||
[BTS_CTR_LCHAN_BORKEN_FROM_WAIT_ACTIV_ACK] = {"lchan_borken:from_state:wait_activ_ack", "Transitions from lchan WAIT_ACTIV_ACK state to BORKEN state"},
|
||||
[BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RF_RELEASE_ACK] = {"lchan_borken:from_state:wait_rf_release_ack", "Transitions from lchan WAIT_RF_RELEASE_ACK state to BORKEN state"},
|
||||
[BTS_CTR_LCHAN_BORKEN_FROM_BORKEN] = {"lchan_borken:from_state:borken", "Transitions from lchan BORKEN state to BORKEN state"},
|
||||
[BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RR_CHAN_MODE_MODIFY_ACK] = {"lchan_borken:from_state:wait_rr_chan_mode_modify_ack", "Transitions from lchan WAIT_RR_CHAN_MODE_MODIFY_ACK state to BORKEN state"},
|
||||
[BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RSL_CHAN_MODE_MODIFY_ACK] = {"lchan_borken:from_state:wait_rsl_chan_mode_modify_ack", "Transitions from lchan RSL_CHAN_MODE_MODIFY_ACK state to BORKEN state"},
|
||||
[BTS_CTR_LCHAN_BORKEN_FROM_UNKNOWN] = {"lchan_borken:from_state:unknown", "Transitions from an unknown lchan state to BORKEN state"},
|
||||
[BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_ACK] = {"lchan_borken:event:chan_activ_ack", "CHAN_ACTIV_ACK received in the lchan BORKEN state"},
|
||||
[BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_NACK] = {"lchan_borken:event:chan_activ_nack", "CHAN_ACTIV_NACK received in the lchan BORKEN state"},
|
||||
|
|
|
@ -18,6 +18,8 @@ enum lchan_fsm_state {
|
|||
LCHAN_ST_WAIT_TS_READY,
|
||||
LCHAN_ST_WAIT_ACTIV_ACK, /*< After RSL Chan Act Ack, lchan is active but RTP not configured. */
|
||||
LCHAN_ST_WAIT_RLL_RTP_ESTABLISH,
|
||||
LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK,
|
||||
LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK,
|
||||
LCHAN_ST_ESTABLISHED, /*< Active and RTP is fully configured. */
|
||||
LCHAN_ST_WAIT_RLL_RTP_RELEASED,
|
||||
LCHAN_ST_WAIT_BEFORE_RF_RELEASE,
|
||||
|
@ -40,10 +42,11 @@ enum lchan_fsm_event {
|
|||
LCHAN_EV_RLL_REL_CONF,
|
||||
LCHAN_EV_RSL_RF_CHAN_REL_ACK,
|
||||
LCHAN_EV_RLL_ERR_IND,
|
||||
|
||||
/* FIXME: not yet implemented: Chan Mode Modify, see assignment_fsm_start(). */
|
||||
LCHAN_EV_CHAN_MODE_MODIF_ACK,
|
||||
LCHAN_EV_CHAN_MODE_MODIF_ERROR,
|
||||
LCHAN_EV_RR_CHAN_MODE_MODIFY_ACK,
|
||||
LCHAN_EV_RR_CHAN_MODE_MODIFY_ERROR,
|
||||
LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK,
|
||||
LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK,
|
||||
LCHAN_EV_REQUEST_MODE_MODIFY,
|
||||
};
|
||||
|
||||
void lchan_fsm_init();
|
||||
|
|
|
@ -1186,10 +1186,12 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
|
|||
case RSL_MT_MODE_MODIFY_ACK:
|
||||
LOG_LCHAN(msg->lchan, LOGL_DEBUG, "CHANNEL MODE MODIFY ACK\n");
|
||||
count_codecs(sign_link->trx->bts, msg->lchan);
|
||||
osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK, NULL);
|
||||
break;
|
||||
case RSL_MT_MODE_MODIFY_NACK:
|
||||
LOG_LCHAN(msg->lchan, LOGL_DEBUG, "CHANNEL MODE MODIFY NACK\n");
|
||||
rate_ctr_inc(&sign_link->trx->bts->bts_ctrs->ctr[BTS_CTR_MODE_MODIFY_NACK]);
|
||||
osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK, NULL);
|
||||
break;
|
||||
case RSL_MT_IPAC_PDCH_ACT_ACK:
|
||||
rc = rsl_rx_ipacc_pdch(msg, "ACT ACK", TS_EV_PDCH_ACT_ACK);
|
||||
|
|
|
@ -379,9 +379,8 @@ static int check_requires_voice_stream(struct gsm_subscriber_connection *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Check if the conn is already associated with an lchan. If yes, we will check
|
||||
* if that lchan is compatible with the preferred rate/codec. If the lchan
|
||||
* turns out to be incompatible we try with the alternate rate/codec. */
|
||||
/* Decide if we should re-use an existing lchan. For this we check if the
|
||||
* current lchan is compatible with one of the requested modes. */
|
||||
static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct assignment_request *req = &conn->assignment.req;
|
||||
|
@ -395,22 +394,10 @@ static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn)
|
|||
for (i = 0; i < req->n_ch_mode_rate; i++)
|
||||
if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate[i])) {
|
||||
conn->lchan->ch_mode_rate = req->ch_mode_rate[i];
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i == req->n_ch_mode_rate)
|
||||
return false;
|
||||
|
||||
if (conn->lchan->tch_mode != conn->lchan->ch_mode_rate.chan_mode) {
|
||||
/* FIXME: send Channel Mode Modify to put the current lchan in the right mode, and kick
|
||||
* off its RTP stream setup code path. See gsm48_lchan_modify() and
|
||||
* gsm48_rx_rr_modif_ack(), and see lchan_fsm.h LCHAN_EV_CHAN_MODE_MODIF_* */
|
||||
LOG_ASSIGNMENT(conn, LOGL_DEBUG,
|
||||
"Current lchan would be compatible, but Channel Mode Modify is not implemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts *bts,
|
||||
|
@ -447,22 +434,57 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts
|
|||
return;
|
||||
|
||||
/* There may be an already existing lchan, if yes, try to work with
|
||||
* the existing lchan */
|
||||
* the existing lchan. */
|
||||
if (reuse_existing_lchan(conn)) {
|
||||
|
||||
/* If the requested mode and the current TCH mode matches up, just send the
|
||||
* assignment complete directly and be done with the assignment procedure. */
|
||||
if (conn->lchan->tch_mode == conn->lchan->ch_mode_rate.chan_mode) {
|
||||
LOG_ASSIGNMENT(conn, LOGL_DEBUG,
|
||||
"Current lchan mode is compatible with requested chan_mode,"
|
||||
" sending BSSMAP Assignment Complete directly."
|
||||
" requested chan_mode=%s; current lchan is %s\n",
|
||||
gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),
|
||||
gsm_lchan_name(conn->lchan));
|
||||
|
||||
send_assignment_complete(conn);
|
||||
/* If something went wrong during send_assignment_complete(),
|
||||
* the fi will be gone from error handling in there. */
|
||||
if (conn->assignment.fi) {
|
||||
assignment_count_result(CTR_ASSIGNMENT_COMPLETED);
|
||||
osmo_fsm_inst_term(conn->assignment.fi, OSMO_FSM_TERM_REGULAR, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* The requested mode does not match the current TCH mode but the lchan is
|
||||
* compatible. We will initiate a mode modify procedure. */
|
||||
LOG_ASSIGNMENT(conn, LOGL_DEBUG,
|
||||
"Current lchan is compatible with requested chan_mode,"
|
||||
" sending BSSMAP Assignment Complete directly."
|
||||
" requested chan_mode=%s; current lchan is %s\n",
|
||||
"Current lchan mode is not compatible with requested chan_mode,"
|
||||
" so we will modify it. requested chan_mode=%s; current lchan is %s\n",
|
||||
gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),
|
||||
gsm_lchan_name(conn->lchan));
|
||||
|
||||
send_assignment_complete(conn);
|
||||
/* If something went wrong during send_assignment_complete(), the fi will be gone from
|
||||
* error handling in there. */
|
||||
if (conn->assignment.fi) {
|
||||
assignment_count_result(CTR_ASSIGNMENT_COMPLETED);
|
||||
osmo_fsm_inst_term(conn->assignment.fi, OSMO_FSM_TERM_REGULAR, 0);
|
||||
}
|
||||
info = (struct lchan_activate_info){
|
||||
.activ_for = FOR_ASSIGNMENT,
|
||||
.for_conn = conn,
|
||||
.chan_mode = conn->lchan->ch_mode_rate.chan_mode,
|
||||
.encr = conn->lchan->encr,
|
||||
.s15_s0 = conn->lchan->ch_mode_rate.s15_s0,
|
||||
.requires_voice_stream = conn->assignment.requires_voice_stream,
|
||||
.msc_assigned_cic = req->msc_assigned_cic,
|
||||
.re_use_mgw_endpoint_from_lchan = conn->lchan,
|
||||
};
|
||||
|
||||
osmo_fsm_inst_dispatch(conn->lchan->fi, LCHAN_EV_REQUEST_MODE_MODIFY, &info);
|
||||
|
||||
/* Since we opted not to allocate a new lchan, the new lchan is still the old lchan. */
|
||||
conn->assignment.new_lchan = conn->lchan;
|
||||
|
||||
/* Also we need to skip the RR assignment, so we jump forward and wait for the lchan_fsm until it
|
||||
* reaches the established state again. */
|
||||
assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ESTABLISHED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -682,6 +704,7 @@ static const struct osmo_fsm_state assignment_fsm_states[] = {
|
|||
.out_state_mask = 0
|
||||
| S(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE)
|
||||
| S(ASSIGNMENT_ST_WAIT_RR_ASS_COMPLETE)
|
||||
| S(ASSIGNMENT_ST_WAIT_LCHAN_ESTABLISHED) /* MODE MODIFY */
|
||||
,
|
||||
},
|
||||
[ASSIGNMENT_ST_WAIT_RR_ASS_COMPLETE] = {
|
||||
|
|
|
@ -655,7 +655,6 @@ int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t mode)
|
|||
|
||||
int gsm48_rx_rr_modif_ack(struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
struct gsm48_chan_mode_modify *mod =
|
||||
(struct gsm48_chan_mode_modify *) gh->data;
|
||||
|
@ -689,15 +688,7 @@ int gsm48_rx_rr_modif_ack(struct msgb *msg)
|
|||
break;
|
||||
}
|
||||
|
||||
/* We've successfully modified the MS side of the channel,
|
||||
* now go on to modify the BTS side of the channel */
|
||||
rc = rsl_chan_mode_modify_req(msg->lchan);
|
||||
|
||||
/* FIXME: we not only need to do this after mode modify, but
|
||||
* also after channel activation */
|
||||
if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && mod->mode != GSM48_CMODE_SIGN)
|
||||
rsl_tx_ipacc_crcx(msg->lchan);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
|
||||
|
@ -970,9 +961,9 @@ static void dispatch_dtap(struct gsm_subscriber_connection *conn,
|
|||
case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
|
||||
rc = gsm48_rx_rr_modif_ack(msg);
|
||||
if (rc < 0)
|
||||
osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_CHAN_MODE_MODIF_ERROR, &rc);
|
||||
osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RR_CHAN_MODE_MODIFY_ERROR, &rc);
|
||||
else
|
||||
osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_CHAN_MODE_MODIF_ACK, msg);
|
||||
osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RR_CHAN_MODE_MODIFY_ACK, msg);
|
||||
break;
|
||||
case GSM48_MT_RR_CLSM_CHG:
|
||||
handle_classmark_chg(conn, msg);
|
||||
|
|
|
@ -59,6 +59,7 @@ bool lchan_may_receive_data(struct gsm_lchan *lchan)
|
|||
switch (lchan->fi->state) {
|
||||
case LCHAN_ST_WAIT_RLL_RTP_ESTABLISH:
|
||||
case LCHAN_ST_ESTABLISHED:
|
||||
case LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -249,7 +250,7 @@ struct osmo_tdef_state_timeout lchan_fsm_timeouts[32] = {
|
|||
} while(0)
|
||||
|
||||
/* Which state to transition to when lchan_fail() is called in a given state. */
|
||||
uint32_t lchan_fsm_on_error[32] = {
|
||||
uint32_t lchan_fsm_on_error[34] = {
|
||||
[LCHAN_ST_UNUSED] = LCHAN_ST_UNUSED,
|
||||
[LCHAN_ST_WAIT_TS_READY] = LCHAN_ST_UNUSED,
|
||||
[LCHAN_ST_WAIT_ACTIV_ACK] = LCHAN_ST_BORKEN,
|
||||
|
@ -260,6 +261,8 @@ uint32_t lchan_fsm_on_error[32] = {
|
|||
[LCHAN_ST_WAIT_RF_RELEASE_ACK] = LCHAN_ST_BORKEN,
|
||||
[LCHAN_ST_WAIT_AFTER_ERROR] = LCHAN_ST_UNUSED,
|
||||
[LCHAN_ST_BORKEN] = LCHAN_ST_BORKEN,
|
||||
[LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK] = LCHAN_ST_BORKEN,
|
||||
[LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK] = LCHAN_ST_BORKEN,
|
||||
};
|
||||
|
||||
#define lchan_fail(fmt, args...) lchan_fail_to(lchan_fsm_on_error[fi->state], fmt, ## args)
|
||||
|
@ -797,6 +800,10 @@ static void lchan_fsm_wait_rll_rtp_establish_onenter(struct osmo_fsm_inst *fi, u
|
|||
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
|
||||
if (lchan->fi_rtp)
|
||||
osmo_fsm_inst_dispatch(lchan->fi_rtp, LCHAN_RTP_EV_LCHAN_READY, 0);
|
||||
/* Prepare an MGW endpoint CI if appropriate (late). */
|
||||
else if (lchan->activate.info.requires_voice_stream)
|
||||
lchan_rtp_fsm_start(lchan);
|
||||
|
||||
}
|
||||
|
||||
static void lchan_fsm_wait_rll_rtp_establish(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
|
@ -833,6 +840,66 @@ static void lchan_fsm_wait_rll_rtp_establish(struct osmo_fsm_inst *fi, uint32_t
|
|||
}
|
||||
}
|
||||
|
||||
static void lchan_fsm_wait_rr_chan_mode_modify_ack_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
|
||||
gsm48_lchan_modify(lchan, lchan->activate.info.chan_mode);
|
||||
}
|
||||
|
||||
static void lchan_fsm_wait_rr_chan_mode_modify_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch (event) {
|
||||
|
||||
case LCHAN_EV_RR_CHAN_MODE_MODIFY_ACK:
|
||||
lchan_fsm_state_chg(LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK);
|
||||
return;
|
||||
|
||||
case LCHAN_EV_RR_CHAN_MODE_MODIFY_ERROR:
|
||||
lchan_fail("Failed to change channel mode on the MS side: %s in state %s\n",
|
||||
osmo_fsm_event_name(fi->fsm, event),
|
||||
osmo_fsm_inst_state_name(fi));
|
||||
return;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void lchan_fsm_wait_rsl_chan_mode_modify_ack_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
|
||||
int rc;
|
||||
|
||||
rc = rsl_chan_mode_modify_req(lchan);
|
||||
if (rc < 0) {
|
||||
lchan_fail("Failed to send rsl message to change the channel mode on the BTS side: state %s\n",
|
||||
osmo_fsm_inst_state_name(fi));
|
||||
}
|
||||
}
|
||||
|
||||
static void lchan_fsm_wait_rsl_chan_mode_modify_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
|
||||
switch (event) {
|
||||
|
||||
case LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK:
|
||||
if (lchan->activate.info.requires_voice_stream)
|
||||
lchan_fsm_state_chg(LCHAN_ST_WAIT_RLL_RTP_ESTABLISH);
|
||||
else
|
||||
lchan_fsm_state_chg(LCHAN_ST_ESTABLISHED);
|
||||
return;
|
||||
|
||||
case LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK:
|
||||
lchan_fail("Failed to change channel mode on the BTS side: %s in state %s\n",
|
||||
osmo_fsm_event_name(fi->fsm, event),
|
||||
osmo_fsm_inst_state_name(fi));
|
||||
return;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void lchan_fsm_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
|
||||
|
@ -909,6 +976,8 @@ static void handle_rll_rel_ind_or_conf(struct osmo_fsm_inst *fi, uint32_t event,
|
|||
static void lchan_fsm_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
|
||||
struct lchan_activate_info *info;
|
||||
struct osmo_mgcpc_ep_ci *use_mgwep_ci;
|
||||
|
||||
switch (event) {
|
||||
case LCHAN_EV_RLL_ESTABLISH_IND:
|
||||
|
@ -935,6 +1004,48 @@ static void lchan_fsm_established(struct osmo_fsm_inst *fi, uint32_t event, void
|
|||
osmo_fsm_inst_state_name(fi));
|
||||
return;
|
||||
|
||||
case LCHAN_EV_REQUEST_MODE_MODIFY:
|
||||
|
||||
/* FIXME: Add missing implementation to handle an already existing RTP voice stream on MODE MODIFY.
|
||||
* there may be transitions from VOICE to SIGNALLING and also from VOICE to VOICE with a different
|
||||
* codec. */
|
||||
if (lchan->fi_rtp) {
|
||||
lchan_fail("MODE MODIFY not implemented when RTP voice stream is already active (VOICE => SIGNALLING, VOICE/CODEC_A => VOICE/CODEC_B)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
info = data;
|
||||
lchan->activate.info = *info;
|
||||
use_mgwep_ci = lchan_use_mgw_endpoint_ci_bts(lchan);
|
||||
|
||||
if (info->chan_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
if (lchan_mr_config(lchan, info->s15_s0) < 0) {
|
||||
lchan_fail("Can not generate multirate configuration IE\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_LCHAN(lchan, LOGL_INFO,
|
||||
"Modification requested: %s voice=%s MGW-ci=%s type=%s tch-mode=%s encr-alg=A5/%u ck=%s\n",
|
||||
lchan_activate_mode_name(lchan->activate.info.activ_for),
|
||||
lchan->activate.info.requires_voice_stream ? "yes" : "no",
|
||||
lchan->activate.info.requires_voice_stream ?
|
||||
(use_mgwep_ci ? osmo_mgcpc_ep_ci_name(use_mgwep_ci) : "new")
|
||||
: "none",
|
||||
gsm_lchant_name(lchan->type),
|
||||
gsm48_chan_mode_name(lchan->tch_mode),
|
||||
(lchan->activate.info.encr.alg_id ? : 1) - 1,
|
||||
lchan->activate.info.encr.key_len ? osmo_hexdump_nospc(lchan->activate.info.encr.key,
|
||||
lchan->activate.info.encr.key_len) : "none");
|
||||
|
||||
/* While the mode is changed the lchan is virtually "not activated", at least
|
||||
* from the FSM implementations perspective */
|
||||
lchan->activate.concluded = false;
|
||||
|
||||
/* Initiate mode modification, start with the MS side (RR) */
|
||||
lchan_fsm_state_chg(LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK);
|
||||
return;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
@ -1090,6 +1201,12 @@ static void lchan_fsm_borken_onenter(struct osmo_fsm_inst *fi, uint32_t prev_sta
|
|||
case LCHAN_ST_BORKEN:
|
||||
ctr = BTS_CTR_LCHAN_BORKEN_FROM_BORKEN;
|
||||
break;
|
||||
case LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK:
|
||||
ctr = BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RR_CHAN_MODE_MODIFY_ACK;
|
||||
break;
|
||||
case LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK:
|
||||
ctr = BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RSL_CHAN_MODE_MODIFY_ACK;
|
||||
break;
|
||||
default:
|
||||
ctr = BTS_CTR_LCHAN_BORKEN_FROM_UNKNOWN;
|
||||
}
|
||||
|
@ -1223,6 +1340,32 @@ static const struct osmo_fsm_state lchan_fsm_states[] = {
|
|||
| S(LCHAN_ST_WAIT_RLL_RTP_RELEASED)
|
||||
,
|
||||
},
|
||||
[LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK] = {
|
||||
.name = "WAIT_CHAN_RR_MODE_MODIFY_ACK",
|
||||
.onenter = lchan_fsm_wait_rr_chan_mode_modify_ack_onenter,
|
||||
.action = lchan_fsm_wait_rr_chan_mode_modify_ack,
|
||||
.in_event_mask = 0
|
||||
| S(LCHAN_EV_RR_CHAN_MODE_MODIFY_ACK)
|
||||
| S(LCHAN_EV_RR_CHAN_MODE_MODIFY_ERROR)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(LCHAN_ST_BORKEN)
|
||||
| S(LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK)
|
||||
,
|
||||
},
|
||||
[LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK] = {
|
||||
.name = "WAIT_RSL_CHAN_MODE_MODIFY_ACK",
|
||||
.onenter = lchan_fsm_wait_rsl_chan_mode_modify_ack_onenter,
|
||||
.action = lchan_fsm_wait_rsl_chan_mode_modify_ack,
|
||||
.in_event_mask = 0
|
||||
| S(LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK)
|
||||
| S(LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(LCHAN_ST_BORKEN)
|
||||
| S(LCHAN_ST_WAIT_RLL_RTP_ESTABLISH)
|
||||
,
|
||||
},
|
||||
[LCHAN_ST_ESTABLISHED] = {
|
||||
.name = "ESTABLISHED",
|
||||
.onenter = lchan_fsm_established_onenter,
|
||||
|
@ -1233,12 +1376,14 @@ static const struct osmo_fsm_state lchan_fsm_states[] = {
|
|||
| S(LCHAN_EV_RLL_ESTABLISH_IND) /* ignored */
|
||||
| S(LCHAN_EV_RTP_ERROR)
|
||||
| S(LCHAN_EV_RTP_RELEASED)
|
||||
| S(LCHAN_EV_REQUEST_MODE_MODIFY)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(LCHAN_ST_UNUSED)
|
||||
| S(LCHAN_ST_WAIT_RLL_RTP_RELEASED)
|
||||
| S(LCHAN_ST_WAIT_BEFORE_RF_RELEASE)
|
||||
| S(LCHAN_ST_WAIT_RF_RELEASE_ACK)
|
||||
| S(LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK)
|
||||
,
|
||||
},
|
||||
[LCHAN_ST_WAIT_RLL_RTP_RELEASED] = {
|
||||
|
@ -1324,8 +1469,10 @@ static const struct value_string lchan_fsm_event_names[] = {
|
|||
OSMO_VALUE_STRING(LCHAN_EV_RLL_REL_CONF),
|
||||
OSMO_VALUE_STRING(LCHAN_EV_RSL_RF_CHAN_REL_ACK),
|
||||
OSMO_VALUE_STRING(LCHAN_EV_RLL_ERR_IND),
|
||||
OSMO_VALUE_STRING(LCHAN_EV_CHAN_MODE_MODIF_ACK),
|
||||
OSMO_VALUE_STRING(LCHAN_EV_CHAN_MODE_MODIF_ERROR),
|
||||
OSMO_VALUE_STRING(LCHAN_EV_RR_CHAN_MODE_MODIFY_ACK),
|
||||
OSMO_VALUE_STRING(LCHAN_EV_RR_CHAN_MODE_MODIFY_ERROR),
|
||||
OSMO_VALUE_STRING(LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK),
|
||||
OSMO_VALUE_STRING(LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue