doc: charts: illustrate new plan for ts and lchans

Add lchan and timeslot FSM charts to illustrate planning of how osmo-bsc should
handle lchan assignment and release.

Modify assignment, handover, lchan-release charts according to the new plan.

Change-Id: I18d60de5ee932c962aad0a532965a55d570bb936
diff --git a/doc/handover.msc b/doc/handover.msc
index 8862dd9..7529de6 100644
--- a/doc/handover.msc
+++ b/doc/handover.msc
@@ -1,170 +1,123 @@
 # Handover between cells, intra-BSC
 msc {
 	hscale=3;
-	ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_gscon[label="BSC conn FSM"], bsc_mgcp[label="BSC mgcp FSM"], mgw[label="MGW"];
+	ms [label="MS via BTS"], bsc_lchan[label="BSC lchan FSM"], bsc_gscon[label="BSC conn FSM"],
+	bsc_mgcp[label="BSC mgcp FSM"], mgw_msc[label="MGW/MSC"];
 
-	ms note mgw [label="intra-BSC Handover sequence"];
+	ms note mgw_msc [label="intra-BSC Handover sequence"];
 
 	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-	bsc box bsc [label="bsc_handover_start(): init conn->ho"];
-	bsc -> bsc_gscon [label="GSCON_EV_HO_START"];
-	bsc <- bsc_gscon [label="bsc_handover_start_gscon()"];
-
-	bsc box bsc [label="lchan_alloc(): pick available lchan"];
-	bsc box bsc [label="rsl_chan_activate_lchan()"];
-
-	--- [label="is the chosen lchan on dynamic timeslot that is currently used as PDCH?"];
-	bts <= bsc [label="i) RSL RF Chan Release of PDCH (Osmocom dyn TS)"];
-	bts <= bsc [label="OR ii) RSL PDCH Deact (ip.access dyn TS)"];
-	bsc -> bsc_gscon [label="bsc_handover_start_gscon() returns early"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_HO_COMPL (no timeout, relies on T3103 below)"];
+	bsc_gscon box bsc_gscon [label="bsc_handover_start(): init conn->ho"];
+	bsc_gscon -> bsc_gscon [label="GSCON_EV_HO_START (intra-BSC)"];
+	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_LCHAN"];
+	bsc_lchan <- bsc_gscon [label="lchan_activate(lchan, FOR_HANDOVER)"];
 	...;
-	bts note bsc_gscon [linecolor="red",
-		label="Osmocom style dyn TS use lchan->act_timer to watch over RF Chan Release, but there
-		seems to be no timer watching over PDCH Deact!"];
+	--- [label="on lchan FSM error or timeout"];
+	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
+	bsc_gscon box bsc_gscon [label="handover_end(fail)"];
+	ms note bsc_gscon [label="MS happily continues on the old lchan."];
+	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
+	--- [label="END: 'on error'"];
 	...;
-	bts => bsc [label="i) RSL RF Chan Release ACK (Osmocom dyn TS)"];
-	bts => bsc [label="OR ii) RSL PDCH Deact ACK (ip.access dyn TS)"];
-	bsc box bsc [label="rsl_chan_activate_lchan() re-invoked"];
-	bts <= bsc [label="RSL Chan Activ"];
-	--- [label="else (no dyn TS switchover)"];
+	...;
 
-	bts <= bsc [label="RSL Chan Activ"];
-	bsc -> bsc_gscon [label="bsc_handover_start_gscon() returns"];
+	--- [label="IF lchan FSM decides that it is an lchan for speech"];
+	bsc_lchan -> bsc_gscon [label="GSCON_EV_ENSURE_MGW_ENDPOINT"];
+	--- [label="IF there is an MGW endpoint for the BTS already (conn->user_plane.fi_bts)"];
+	bsc_gscon box bsc_gscon [label="handover_created_mgw_endpoint = false"];
+	bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
+	--- [label="ELSE: no MGW endpoint for the BTS side yet"];
+	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_CRCX_BTS"];
+	bsc_gscon box bsc_gscon [label="handover_created_mgw_endpoint = true"];
+	bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
+	bsc_mgcp => mgw_msc [label="CRCX (for BTS)"];
+	bsc_mgcp abox bsc_mgcp [label="ST_CRCX_RESP (MGCP_MGW_TIMEOUT = 4s)"];
+	bsc_gscon note bsc_mgcp [label="conn FSM relies on mgcp FSM timeout"];
+	...;
+	--- [label="On Timeout"];
+	bsc_mgcp note bsc_mgcp [label="On timeout, the MGCP FSM will terminate, emitting the parent_term
+		event set upon mgcp_conn_create():"];
+	bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_FAIL_BTS"];
+	bsc_gscon note bsc_gscon [label="GSCON_EV_MGW_FAIL_BTS is handled by the conn FSM allstate
+		handler. It sets conn->user_plane.fi_bts = NULL."];
+	bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_ERROR"];
+	bsc_lchan note bsc_gscon [label="conn FSM error handler exits and relies on the lchan FSM
+		signalling error, which should actually happen immediately:"];
+	bsc_gscon <- bsc_lchan [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
+	bsc_gscon box bsc_gscon [label="handover_end(fail)"];
+	--- [label="IF handover_created_mgw_endpoint == true"];
+	bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
 	---;
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_HO_COMPL (no timeout, relies on T3103 below)"];
+	ms note bsc_gscon [label="MS happily continues on the old lchan."];
+	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
+	--- [label="END: 'On Timeout'"];
+	...;
 
+	bsc_mgcp <= mgw_msc [label="CRCX OK (for BTS)"];
+	bsc_mgcp box bsc_mgcp [label="libosmo-mgcp-client fsm_crcx_resp_cb()"];
+	bsc_mgcp abox bsc_mgcp [label="ST_READY"];
+	bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_CRCX_RESP_BTS"];
+	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_LCHAN"];
+	bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
+	--- [label="END: lchan FSM decides that it is an lchan for speech"];
 	...;
-	bts note bsc_gscon [linecolor="red",
-	  label="There seems to be no timer watching out for RSL Chan Activ ACK/NACK!"];
 	...;
-	bts => bsc [label="RSL Chan Activ ACK"];
-	bsc box bsc [label="rsl_rx_chan_act_ack()"];
-	bsc box bsc [label="Stop lchan->act_timer"];
-	bsc box bsc [label="lchan->state = LCHAN_S_ACTIVE"];
-	bsc -> bsc [label="S_LCHAN_ACTIVATE_ACK"];
-	bsc box bsc [label="handover_logic.c ho_logic_sig_cb()"];
-	bsc box bsc [label="ho_chan_activ_ack()"];
-	bsc note bsc [label="gsm48_send_ho_cmd()"];
-	ms <= bsc [label="RR Handover Command"];
-	bsc abox bsc [label="start T3103"];
-	--- [label="is BTS using IPA Abis? (osmo-bts, ip.access)"];
-	bts <= bsc [label="IPACC CRCX"];
-	bsc -> bsc [label="ho_chan_activ_ack() returns"];
-	bts note bsc [linecolor="red",
-	  label="There seems to be no timer watching over IPACC CRCX ACK/NACK!
-	         If no response is received, we simply ignore that fact and carry on as if
-		 everything was fine."];
-	...;
-	bts note bsc [label="The IPACC CRCX and MDCX ACKs may come back at any time:
-			     before or after the Handover Detect, before or after Handover Complete."];
-	bts note bsc_mgcp [linecolor="red",
-	  label="The CRCX ACK contains vital information for routing the RTP stream.
-	         If the CRCX ACK were very slow, we would not know which RTP/RTPC ports
-		 to point the MGW at, below at mgcp_conn_modify()!
-		 Even though this being unrealistic, we must make sure to receive a CRCX ACK."];
-	...;
-	bsc box bsc [label="osmo_bsc_audio.c"];
-	bts => bsc [label="IPACC CRCX ACK"];
-	bts <= bsc [label="IPACC MDCX"];
-	...;
-	bts note bsc [linecolor="red",
-	  label="There seems to be no timer watching over IPACC MDCX ACK/NACK!
-	         If no response is received, we simply ignore that fact and carry on as if
-		 everything was fine."];
-	...;
-	bts => bsc [label="IPACC MDCX ACK"];
-	bts note bsc [label="IPACC MDCX ACK triggers no events or actions"];
-	---;
 
-	...;
-	ms => bsc [label="RR Handover Detect"];
-	bsc -> bsc [label="S_LCHAN_HANDOVER_DETECT"];
-	bsc box bsc [label="ho_rsl_detect(): no action, only logging"];
-	bsc note bsc_gscon [label="Handover Detect triggers no events or actions"];
-	bsc note bsc_gscon [linecolor="red",
-	  label="upon Handover Detect, we should already start re-routing the RTP!
-	         Instead we wait for Handover Complete."];
+	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ACTIVE"];
+	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_DETECT\nT3103"];
+	bsc_gscon box bsc_gscon [label="gsm48_send_ho_cmd()"];
+	ms <= bsc_gscon [label="RR Handover Command"];
 
 	...;
-	ms => bsc [label="RR Handover Complete"];
-	bsc -> bsc [label="S_LCHAN_HANDOVER_COMPL"];
-	bsc box bsc [label="handover_logic.c ho_logic_sig_cb()"];
-	bsc box bsc [label="ho_gsm48_ho_compl()"];
-	bsc box bsc [label="stop T3103"];
-	bts note bsc_gscon [label="If anything goes wrong from this point on, we will not move back
-	                           to the old lchan: would be pointless after Handover Complete."];
-	bsc note bsc [label="officially take over new lchan: conn->lchan = ho->new_lchan"];
-
-	--- [label="Release old lchan"];
-	bsc box bsc [label="_lchan_handle_release(sacch_deact=0)"];
-	bsc box bsc [label="rsl_release_sapis_from(start=1)"];
-	bts <= bsc [label="RSL Release Request (Local End)..."];
-	bts <= bsc [label="...for each SAPI except link_id=0"];
-	bsc box bsc [label="rsl_release_request(link_id=0)"];
-	bts <= bsc [label="RSL Release Request (Local End) for link_id=0"];
-	bsc box bsc [label="_lchan_handle_release() returns here, the remaining release is asynchronous;
-	                    see `End: 'Release old lchan'` below."];
-	...;
-	bts note bsc_gscon [linecolor="red",
-	  label="There seems to be no timer watching over RSL Release Request!"];
-	...;
-	bts => bsc [label="RSL Release Confirm..."];
-	bts => bsc [label="...for each SAPI and link_id=0"];
-	bsc abox bsc [label="start T3111"];
-	...;
-	bsc box bsc [label="T3111 expires"];
-	bsc abox bsc [label="Start lchan->act_timer with lchan_deact_tmr_cb"];
-	bts <= bsc [label="RSL RF Channel Release"];
-	...;
 	--- [label="On timeout"];
-	bsc box bsc [label="lchan_deact_tmr_cb()"];
-	bsc box bsc [label="rsl_lchan_mark_broken(): state=LCHAN_S_BROKEN"];
-	bsc box bsc [label="lchan_free()"];
-	bsc -> bsc [label="S_LCHAN_UNEXPECTED_RELEASE"];
-	bsc box bsc [label="bsc_api.c handle_release()"];
-	bsc box bsc [label="bsc->clear_request()"];
-	bsc box bsc [label="bsc_clear_request encodes a BSSMAP Clear Request message and passes it on
-	                    to the conn FSM as data argument via:"];
-	bsc -> bsc_gscon [label="GSCON_EV_TX_SCCP"];
-	bsc_gscon rbox bsc_gscon [label="BSSMAP Clear Request to MSC"];
-	bsc note bsc_gscon [linecolor="red",
-	  label="During Handover, we actually release the entire conn just because we failed to
-	         gracefully release the old lchan. That is obviously nonsense."];
-	bsc note bsc [label="Stop T3101 (but was not active in this code path)"];
-	bsc -> bsc [label="S_CHALLOC_FREED"];
-	--- [label="End: 'On timeout'"];
-	...;
-	bts => bsc [label="RSL RF Channel Release Ack"];
-	bsc box bsc [label="Stop lchan->act_timer"];
-	bsc box bsc [label="Stop lchan->T3111"];
+	bsc_lchan <- bsc_gscon [label="NEW lchan: LCHAN_EV_RELEASE"];
+	ms <=> bsc_lchan [label="release procedure (async)"];
+	bsc_gscon box bsc_gscon [label="handover_end(fail)"];
+	--- [label="IF handover_created_mgw_endpoint == true"];
+	bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
 	---;
+	ms note bsc_gscon [label="MS happily continues on the old lchan."];
+	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
+	--- [label="END: On timeout"];
+	...;
+	ms => bsc_gscon [label="RR Handover Detect"];
 
-	bsc box bsc [label="still in ho_gsm48_ho_compl()"];
-	bsc note bsc [label="handover_free(), conn->ho = NULL"];
-	bsc -> bsc_gscon [label="GSCON_EV_HO_COMPL"];
-	bsc note bsc_gscon [linecolor="orange",
-	  label="Handover information is cleared before signalling the conn FSM.
-	         That means the conn FSM cannot possibly log sensible information about exactly
-		 which Handover has just completed."];
-
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_MDCX_BTS_HO
-					 (MGCP_MGW_TIMEOUT=4s with MGCP_MGW_HO_TIMEOUT_TIMER_NR)"];
-
+	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_MDCX_BTS\ncontinue T3103"];
+	bsc_gscon -> bsc_lchan [label="OLD lchan: LCHAN_EV_RELEASE"];
+	ms <=> bsc_lchan [label="release procedure (async)"];
+	bsc_lchan note bsc_gscon [label="officially take over new lchan: conn->lchan = ho->new_lchan"];
 	bsc_gscon -> bsc_mgcp [label="mgcp_conn_modify()"];
 	bsc_mgcp note bsc_mgcp [label="mgcp FSM that was established for old lchan, for BTS side"];
-	bsc_mgcp => mgw [label="MDCX (for BTS)"];
+	bsc_mgcp abox bsc_mgcp [label="ST_MDCX_RESP"];
+	bsc_mgcp => mgw_msc [label="MDCX (for BTS)"];
 	...;
-	bsc_gscon note mgw [
-	  label="If we get no MDCX ACK, the MGCP FSM terminates, and emits GSCON_EV_MGW_FAIL_BTS.
-		 Besides invalidating the MGCP FSM pointer, this event has no
-		 effect in ST_WAIT_MDCX_BTS_HO, and we rely on above conn FSM
-		 timeout instead."];
-	bsc_gscon note bsc_gscon [linecolor="red",
-	  label="A timeout of ST_WAIT_MDCX_BTS_HO simply transitions back to ST_ACTIVE!
-	         Even though the MGW failed, we carry on as if everything were fine."];
+	--- [label="Should the Handover Complete arrive early"];
+	ms => bsc_gscon [label="RR Handover Complete"];
+	bsc_gscon box bsc_gscon [label="handover_complete_received = true"];
+	---;
 	...;
-	bsc_mgcp <= mgw [label="MDCX OK"];
+	--- [label="On timeout of the mgcp FSM"];
+	bsc_gscon note mgw_msc [label="MGCP FSM terminates"];
+	bsc_gscon <- bsc_mgcp [label="GSCON_EV_MGW_FAIL_BTS"];
+	bsc_lchan note bsc_gscon [label="The phone has already taken on the new lchan, but now we happen
+		to not be able to use it. The only sensible thing is to end the conn."];
+	bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
+	bsc_gscon => mgw_msc [label="BSSMAP Clear Request\n(Equipment Failure)"];
+	bsc_lchan <- bsc_gscon [label="NEW lchan: LCHAN_EV_RELEASE"];
+	ms <=> bsc_lchan [label="release procedure (async)"];
+	bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
+	...;
+	bsc_mgcp <= mgw_msc [label="MDCX OK"];
+	bsc_mgcp abox bsc_mgcp [label="ST_READY"];
 	bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_MDCX_RESP_BTS"];
+	--- [label="IF !handover_complete_received"];
+	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_COMPLETE\ncontinue T3103"];
+	--- [label="ELSE"];
+	bsc_gscon -> bsc_gscon [label="gscon_handover_post_complete()"];
+	---;
+	...;
+	ms => bsc_gscon [label="RR Handover Complete"];
+	bsc_gscon box bsc_gscon [label="gscon_handover_post_complete()"];
+	bsc_gscon note bsc_gscon [label="handover_end(success), conn->ho = NULL"];
 	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
 }