Change in osmo-bsc[master]: lchan_fsm: make rsl mode-modify working again

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Fri Sep 4 07:34:15 UTC 2020


laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/19792 )

Change subject: lchan_fsm: make rsl mode-modify working again
......................................................................

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
---
M doc/assignment-fsm.dot
M doc/assignment.msc
M doc/lchan-fsm.dot
M doc/lchan.msc
M include/osmocom/bsc/bts.h
M include/osmocom/bsc/lchan_fsm.h
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/assignment_fsm.c
M src/osmo-bsc/gsm_04_08_rr.c
M src/osmo-bsc/lchan_fsm.c
10 files changed, 252 insertions(+), 47 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved
  pespin: Looks good to me, but someone else must approve



diff --git a/doc/assignment-fsm.dot b/doc/assignment-fsm.dot
index 5a3a2b9..c218153 100644
--- a/doc/assignment-fsm.dot
+++ b/doc/assignment-fsm.dot
@@ -22,6 +22,7 @@
 	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]
diff --git a/doc/assignment.msc b/doc/assignment.msc
index 4e690a8..fae088f 100644
--- a/doc/assignment.msc
+++ b/doc/assignment.msc
@@ -9,6 +9,14 @@
 	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"];
 
 	|||;
diff --git a/doc/lchan-fsm.dot b/doc/lchan-fsm.dot
index b726b0c..fe35903 100644
--- a/doc/lchan-fsm.dot
+++ b/doc/lchan-fsm.dot
@@ -38,4 +38,10 @@
 	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]
 }
diff --git a/doc/lchan.msc b/doc/lchan.msc
index e2caa48..b0e32d6 100644
--- a/doc/lchan.msc
+++ b/doc/lchan.msc
@@ -129,6 +129,26 @@
 	...;
 	...;
 
+	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"];
diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index 5506a86..a50c70e 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -50,6 +50,8 @@
 	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 @@
 	[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"},
diff --git a/include/osmocom/bsc/lchan_fsm.h b/include/osmocom/bsc/lchan_fsm.h
index 55ab024..df3ed22 100644
--- a/include/osmocom/bsc/lchan_fsm.h
+++ b/include/osmocom/bsc/lchan_fsm.h
@@ -18,6 +18,8 @@
 	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 @@
 	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();
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index d3f7de2..03d53c5 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -1186,10 +1186,12 @@
 	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);
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index ca29daa..fde028e 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -379,9 +379,8 @@
 	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 @@
 	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 @@
 		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 @@
 		.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] = {
diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c
index be114f0..848f623 100644
--- a/src/osmo-bsc/gsm_04_08_rr.c
+++ b/src/osmo-bsc/gsm_04_08_rr.c
@@ -655,7 +655,6 @@
 
 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 @@
 		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 @@
 		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);
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 26bfd29..115c3da 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -59,6 +59,7 @@
 	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 @@
 	} 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 @@
 	[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 @@
 	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_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 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 @@
 			   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 @@
 	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 @@
 			| 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 @@
 			| 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 @@
 	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),
 	{}
 };
 

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/19792
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I2c5a283b1ee33745cc1fcfcc09a0f9382224e2eb
Gerrit-Change-Number: 19792
Gerrit-PatchSet: 5
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier at sysmocom.de>
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-CC: fixeria <vyanitskiy at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200904/d3dbfcef/attachment.htm>


More information about the gerrit-log mailing list