lchan_fsm: split off lchan_rtp_fsm, establish RTP a bit earlier

Change-Id: Id7a4407d9b63be05ce63f5f2768b7d7e3d5c86fb
diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index f73417e..57837ec 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -29,6 +29,7 @@
 	handover_vty.h \
 	ipaccess.h \
 	lchan_fsm.h \
+	lchan_rtp_fsm.h \
 	lchan_select.h \
 	meas_feed.h \
 	meas_rep.h \
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index d8d10c9..12bc5c3 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -499,13 +499,15 @@
 	char *name;
 
 	struct osmo_fsm_inst *fi;
+	struct osmo_fsm_inst *fi_rtp;
 	struct mgwep_ci *mgw_endpoint_ci_bts;
 
 	struct {
 		enum lchan_activate_mode activ_for;
+		bool activ_ack; /*< true as soon as RSL Chan Activ Ack is received */
 		bool concluded; /*< true as soon as LCHAN_ST_ESTABLISHED is reached */
 		bool requires_voice_stream;
-		bool mgw_endpoint_available;
+		bool wait_before_switching_rtp; /*< true = requires LCHAN_EV_READY_TO_SWITCH_RTP */
 		uint16_t msc_assigned_cic;
 		enum gsm0808_cause gsm0808_error_cause;
 		struct gsm_lchan *re_use_mgw_endpoint_from_lchan;
diff --git a/include/osmocom/bsc/lchan_fsm.h b/include/osmocom/bsc/lchan_fsm.h
index 49701c1..35b8847 100644
--- a/include/osmocom/bsc/lchan_fsm.h
+++ b/include/osmocom/bsc/lchan_fsm.h
@@ -16,13 +16,9 @@
 	LCHAN_ST_UNUSED,
 	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_ESTABLISH,
-	LCHAN_ST_WAIT_MGW_ENDPOINT_AVAILABLE,
-	LCHAN_ST_WAIT_IPACC_CRCX_ACK,
-	LCHAN_ST_WAIT_IPACC_MDCX_ACK,
-	LCHAN_ST_WAIT_MGW_ENDPOINT_CONFIGURED,
+	LCHAN_ST_WAIT_RLL_RTP_ESTABLISH,
 	LCHAN_ST_ESTABLISHED, /*< Active and RTP is fully configured. */
-	LCHAN_ST_WAIT_SAPIS_RELEASED,
+	LCHAN_ST_WAIT_RLL_RTP_RELEASED,
 	LCHAN_ST_WAIT_BEFORE_RF_RELEASE,
 	LCHAN_ST_WAIT_RF_RELEASE_ACK,
 	LCHAN_ST_WAIT_AFTER_ERROR,
@@ -36,13 +32,9 @@
 	LCHAN_EV_RSL_CHAN_ACTIV_ACK,
 	LCHAN_EV_RSL_CHAN_ACTIV_NACK,
 	LCHAN_EV_RLL_ESTABLISH_IND,
-	LCHAN_EV_MGW_ENDPOINT_AVAILABLE,
-	LCHAN_EV_MGW_ENDPOINT_CONFIGURED,
-	LCHAN_EV_MGW_ENDPOINT_ERROR,
-	LCHAN_EV_IPACC_CRCX_ACK,
-	LCHAN_EV_IPACC_CRCX_NACK,
-	LCHAN_EV_IPACC_MDCX_ACK,
-	LCHAN_EV_IPACC_MDCX_NACK,
+	LCHAN_EV_RTP_READY,
+	LCHAN_EV_RTP_ERROR,
+	LCHAN_EV_RTP_RELEASED,
 	LCHAN_EV_RLL_REL_IND,
 	LCHAN_EV_RLL_REL_CONF,
 	LCHAN_EV_RSL_RF_CHAN_REL_ACK,
@@ -66,11 +58,13 @@
 	 * When a dyn TS was selected, the lchan->type has been set to the desired rate. */
 	enum gsm48_chan_mode chan_mode;
 	bool requires_voice_stream;
+	bool wait_before_switching_rtp;
 	uint16_t msc_assigned_cic;
 	struct gsm_lchan *old_lchan;
 };
 
 void lchan_activate(struct gsm_lchan *lchan, struct lchan_activate_info *info);
+void lchan_ready_to_switch_rtp(struct gsm_lchan *lchan);
 
 static inline const char *lchan_state_name(struct gsm_lchan *lchan)
 {
@@ -86,4 +80,5 @@
 bool lchan_may_receive_data(struct gsm_lchan *lchan);
 
 void lchan_forget_conn(struct gsm_lchan *lchan);
-void lchan_forget_mgw_endpoint(struct gsm_lchan *lchan);
+
+void lchan_set_last_error(struct gsm_lchan *lchan, const char *fmt, ...);
diff --git a/include/osmocom/bsc/lchan_rtp_fsm.h b/include/osmocom/bsc/lchan_rtp_fsm.h
new file mode 100644
index 0000000..fa0e746
--- /dev/null
+++ b/include/osmocom/bsc/lchan_rtp_fsm.h
@@ -0,0 +1,45 @@
+/* osmo-bsc API to manage lchans, logical channels in GSM cells. */
+#pragma once
+
+#define LOG_LCHAN_RTP(lchan, level, fmt, args...) do { \
+	if (lchan->fi_rtp) \
+		LOGPFSML(lchan->fi_rtp, level, fmt, ## args); \
+	else \
+		LOGP(DLMGCP, level, "%s (not initialized) " fmt, gsm_lchan_name(lchan), \
+		     ## args); \
+	} while(0)
+
+struct gsm_lchan;
+
+enum lchan_rtp_fsm_state {
+	LCHAN_RTP_ST_WAIT_MGW_ENDPOINT_AVAILABLE,
+	LCHAN_RTP_ST_WAIT_LCHAN_READY,
+	LCHAN_RTP_ST_WAIT_IPACC_CRCX_ACK,
+	LCHAN_RTP_ST_WAIT_IPACC_MDCX_ACK,
+	LCHAN_RTP_ST_WAIT_READY_TO_SWITCH_RTP,
+	LCHAN_RTP_ST_WAIT_MGW_ENDPOINT_CONFIGURED,
+	LCHAN_RTP_ST_READY,
+	LCHAN_RTP_ST_ROLLBACK,
+	LCHAN_RTP_ST_ESTABLISHED,
+};
+
+enum lchan_rtp_fsm_event {
+	LCHAN_RTP_EV_LCHAN_READY,
+	LCHAN_RTP_EV_READY_TO_SWITCH_RTP,
+	LCHAN_RTP_EV_MGW_ENDPOINT_AVAILABLE,
+	LCHAN_RTP_EV_MGW_ENDPOINT_ERROR,
+	LCHAN_RTP_EV_IPACC_CRCX_ACK,
+	LCHAN_RTP_EV_IPACC_CRCX_NACK,
+	LCHAN_RTP_EV_IPACC_MDCX_ACK,
+	LCHAN_RTP_EV_IPACC_MDCX_NACK,
+	LCHAN_RTP_EV_READY_TO_SWITCH,
+	LCHAN_RTP_EV_MGW_ENDPOINT_CONFIGURED,
+	LCHAN_RTP_EV_ROLLBACK, /*< Give the RTP back to the old lchan, if any */
+	LCHAN_RTP_EV_ESTABLISHED, /*< All done, forget about the old lchan, if any */
+	LCHAN_RTP_EV_RELEASE,
+};
+
+void lchan_rtp_fsm_start(struct gsm_lchan *lchan);
+struct mgwep_ci *lchan_use_mgw_endpoint_ci_bts(struct gsm_lchan *lchan);
+bool lchan_rtp_established(struct gsm_lchan *lchan);
+void lchan_forget_mgw_endpoint(struct gsm_lchan *lchan);