Change in osmo-bsc[master]: doc: update/fix FSM charts

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/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Sat Jul 28 10:43:54 UTC 2018


Neels Hofmeyr has submitted this change and it was merged. ( https://gerrit.osmocom.org/9667 )

Change subject: doc: update/fix FSM charts
......................................................................

doc: update/fix FSM charts

These reflect the plan for refactoring, and will be implemented by
I82e3f918295daa83274a4cf803f046979f284366 and
Id7a4407d9b63be05ce63f5f2768b7d7e3d5c86fb

Change-Id: I29e31b753e23a4207662e0e385a337e7df836f45
---
M doc/Makefile.am
A doc/assignment-fsm.dot
M doc/assignment.msc
A doc/handover-inter-bsc-in-fsm.dot
A doc/handover-inter-bsc-in.msc
D doc/handover-inter-bsc-mo.msc
D doc/handover-inter-bsc-mt.msc
A doc/handover-inter-bsc-out-fsm.dot
A doc/handover-inter-bsc-out.msc
A doc/handover-intra-bsc-fsm.dot
M doc/handover.msc
M doc/lchan-fsm.dot
D doc/lchan-release.msc
A doc/lchan-rtp-fsm.dot
M doc/lchan.msc
A doc/legend_for_fsm_diagrams.dot
A doc/legend_for_ladder_diagrams.msc
A doc/mgw-endpoint-fsm.dot
A doc/mgw-endpoint.msc
D doc/ms-channel-request.msc
M doc/timeslot-fsm.dot
M doc/timeslot.msc
M doc/ts-and-lchan-fsm-lifecycle.msc
23 files changed, 833 insertions(+), 865 deletions(-)

Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved



diff --git a/doc/Makefile.am b/doc/Makefile.am
index ca0470d..9b87bf3 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -3,20 +3,27 @@
 	$(NULL)
 
 msc: \
+	$(builddir)/legend_for_ladder_diagrams.png \
 	$(builddir)/handover.png \
 	$(builddir)/assignment.png \
-	$(builddir)/lchan-release.png \
-	$(builddir)/ms-channel-request.png \
 	$(builddir)/timeslot.png \
 	$(builddir)/lchan.png \
 	$(builddir)/ts-and-lchan-fsm-lifecycle.png \
-	$(builddir)/handover-inter-bsc-mo.png \
-	$(builddir)/handover-inter-bsc-mt.png \
+	$(builddir)/handover-inter-bsc-out.png \
+	$(builddir)/handover-inter-bsc-in.png \
+	$(builddir)/mgw-endpoint.png \
 	$(NULL)
 
 dot: \
+	$(builddir)/legend_for_fsm_diagrams.png \
+	$(builddir)/assignment-fsm.png \
 	$(builddir)/timeslot-fsm.png \
 	$(builddir)/lchan-fsm.png \
+	$(builddir)/lchan-rtp-fsm.png \
+	$(builddir)/mgw-endpoint-fsm.png \
+	$(builddir)/handover-intra-bsc-fsm.png \
+	$(builddir)/handover-inter-bsc-out-fsm.png \
+	$(builddir)/handover-inter-bsc-in-fsm.png \
 	$(NULL)
 
 $(builddir)/%.png: $(srcdir)/%.msc
diff --git a/doc/assignment-fsm.dot b/doc/assignment-fsm.dot
new file mode 100644
index 0000000..5a3a2b9
--- /dev/null
+++ b/doc/assignment-fsm.dot
@@ -0,0 +1,42 @@
+digraph G {
+rankdir=TB
+labelloc=t; label="Assignment FSM"
+	
+	WAIT_LCHAN_ACTIVE
+	WAIT_RR_ASS_COMPLETE
+	WAIT_LCHAN_ESTABLISHED
+	WAIT_MGW_ENDPOINT_TO_MSC
+	terminate [shape=octagon]
+	
+	gscon [label="conn FSM",shape=box3d]
+	gscon2 [label="conn FSM",shape=box3d]
+	lchan [label="lchan FSM\n(new lchan)",shape=box3d]
+	old_lchan [label="old lchan",shape=box3d]
+
+	bssap [label="osmo_bsc_bssap.c",shape=box]
+
+	invisible [style="invisible"]
+	invisible -> bssap [label="BSSMAP Assignment Request",style=dotted]
+	invisible -> old_lchan [style=invisible,arrowhead=none]
+
+	bssap -> gscon [label="GSCON_EV_ASSIGNMENT_START\ndata=struct assignment_request",style=dotted]
+
+	gscon -> WAIT_LCHAN_ACTIVE [label="assignment_fsm_start()",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]
+
+	WAIT_LCHAN_ACTIVE -> WAIT_RR_ASS_COMPLETE
+
+	WAIT_RR_ASS_COMPLETE -> old_lchan [label="RR Assignment\nCommand",style=dotted,constraint=false]
+	lchan -> WAIT_RR_ASS_COMPLETE [label="RR Assignment\nComplete",style=dotted]
+
+	WAIT_RR_ASS_COMPLETE -> WAIT_LCHAN_ESTABLISHED
+
+	WAIT_LCHAN_ESTABLISHED -> WAIT_MGW_ENDPOINT_TO_MSC [label="TCH"]
+	WAIT_LCHAN_ESTABLISHED -> terminate [label="non-TCH"]
+	WAIT_MGW_ENDPOINT_TO_MSC -> terminate
+	WAIT_MGW_ENDPOINT_TO_MSC -> gscon2 [label="gscon_connect_\nmgw_to_msc()",style=dotted]
+	gscon2 -> WAIT_MGW_ENDPOINT_TO_MSC [label="ASSIGNMENT_EV_\nMSC_MGW_OK",style=dotted]
+	terminate -> gscon2 [label="GSCON_EV_\nASSIGNMENT_END",style=dotted]
+}
diff --git a/doc/assignment.msc b/doc/assignment.msc
index 9f10ea1..4e690a8 100644
--- a/doc/assignment.msc
+++ b/doc/assignment.msc
@@ -1,126 +1,72 @@
 msc {
-	hscale=3;
-	ms [label="MS/BTS"], bsc_lchan[label="BSC lchan FSM"],
-	bsc_gscon[label="BSC conn FSM"], bsc_mgcp[label="BSC mgcp FSM"], mgw_msc[label="MGW/MSC"];
+	hscale=2;
+	ms [label="MS/BTS"], lchan[label="BSC lchan FSM"], ass[label="BSC Assignment FSM"],
+	gscon[label="BSC conn FSM"], msc_[label="MSC"];
 
-	ms note mgw_msc [label="lchan allocation sequence for BSSMAP Assignment Request"];
+	ms note msc_ [label="lchan allocation sequence for BSSMAP Assignment Request"];
 
-	bsc_gscon <= mgw_msc [label="BSSMAP Assignment Request"];
-	bsc_gscon abox bsc_gscon [label="ST_ASSIGNMENT_\nWAIT_LCHAN"];
+	gscon <= msc_ [label="BSSMAP Assignment Request"];
+	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()"];
+	ass abox ass [label="ASSIGNMENT_ST_\nWAIT_LCHAN_ACTIVE"];
 
-	bsc_lchan <- bsc_gscon [label="lchan_select_by_chan_mode(chan_mode)"];
 	|||;
-	--- [label="IF returned lchan is NULL"];
-	bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
+	--- [label="On any error (no lchan, etc.)"];
+	ass box ass [label="on_assignment_failure()"];
+	ass => msc_ [label="BSSMAP Assignment Failure"];
+	ass abox ass [label="terminate"];
+	ass -> gscon [label="GSCON_EV_ASSIGNMENT_END"];
+	gscon abox gscon [label="ST_ACTIVE"];
 	---;
 	|||;
-	bsc_gscon box bsc_gscon [label="store lchan pointer in conn->lchan_for_assignment"];
-	bsc_lchan <- bsc_gscon [label="lchan_activate(FOR_ASSIGNMENT)"];
+	lchan abox lchan [label="UNUSED"];
+	ass box ass [label="conn->assignment.new_lchan = lchan_select_by_chan_mode()"];
+	lchan <- ass [label="lchan_activate(FOR_ASSIGNMENT)"];
+	lchan abox lchan [label="WAIT_TS_READY"];
+	lchan rbox lchan [label="most details omitted, see lchan_fsm and lchan_rtp_fsm diagrams"];
 	...;
 	|||;
 	--- [label="on lchan FSM error or timeout"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
-	bsc_gscon box bsc_gscon [label="'forget' all about conn->lchan_for_assignment"];
-	bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
+	lchan -> ass [label="ASSIGNMENT_EV_LCHAN_ERROR"];
+	ass box ass [label="on_assignment_failure()"];
+	ass rbox gscon [label="See 'On any error' above"];
 	--- [label="END: 'on error'"];
 	...;
 	...;
 
-	--- [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 -> 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_ASSIGNMENT_\nWAIT_CRCX_BTS"];
-	bsc_gscon box bsc_gscon [label="assignment_created_mgw_endpoint = true"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
-	bsc_mgcp abox bsc_mgcp [label="ST_CRCX_RESP (MGCP_MGW_TIMEOUT = 4s)"];
-	bsc_mgcp => mgw_msc [label="CRCX (for BTS)"];
-	bsc_gscon note bsc_mgcp [label="conn FSM relies on mgcp FSM timeout"];
+	lchan abox lchan [label="LCHAN_ST_WAIT_ACTIV_ACK"];
+	ms <= lchan [label="RSL Chan Activ"];
 	...;
-	--- [label="On Timeout"];
-	bsc_mgcp note bsc_mgcp [label="On timeouit, 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 timeout 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 abox bsc_gscon [label="ST_ACTIVE"];
-	bsc_gscon box bsc_gscon [label="'forget' all about conn->lchan_for_assignment"];
-	bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
-	--- [label="END: 'On Timeout'"];
+	ms => lchan [label="RSL Chan Activ ACK"];
+	lchan -> ass [label="ASSIGNMENT_EV_LCHAN_ACTIVE"];
+	ass abox ass [label="ASSIGNMENT_ST_\nWAIT_RR_ASS_COMPLETE"];
+	ms <= ass [label="RR Assignment Command"];
+	lchan note ass [label="The lchan FSM will continue with RSL and RTP while the Assignment FSM waits.
+		ASSIGNMENT_EV_LCHAN_ESTABLISHED means that both RSL and RTP are established.
+		Usually, RTP will be done first, and the ASSIGNMENT_EV_LCHAN_ESTABLISHED may be
+		received even before ASSIGNMENT_EV_RR_ASSIGNMENT_COMPLETE.
+		assignment_fsm_wait_lchan_established_onenter() decides whether to wait or not."];
 	...;
+	ms => lchan [label="RSL EST IND"];
+	lchan -> ass [label="ASSIGNMENT_EV_LCHAN_ESTABLISHED",ID="(may come as early as this, or...)"];
+	ms => ass [label="RR Assignment Complete (came with EST IND)"];
+	ass abox ass [label="ASSIGNMENT_ST_\nWAIT_LCHAN_ESTABLISHED"];
+	--- [label="IF lchan is not in LCHAN_ST_ESTABLISHED yet (waiting for RTP)"];
+	...;
+	lchan rbox lchan [label="when lchan RTP FSM is done with setting up RTP"];
+	lchan -> ass [label="ASSIGNMENT_EV_LCHAN_ESTABLISHED",ID="(...may come only now)"];
+	---;
+	ass abox ass [label="ASSIGNMENT_ST_WAIT_\nMGW_ENDPOINT_TO_MSC"];
+	ass -> gscon [label="gscon_connect_mgw_to_msc()"];
+	...;
+	ass <- gscon [label="ASSIGNMENT_EV_MSC_MGW_OK"];
+	ass box ass [label="assignment_success()"];
+	ass => msc_ [label="BSSMAP Assignment Complete"];
+	ass -> gscon [label="gscon_change_primary_lchan()"];
+	lchan <- gscon [label="LCHAN_RTP_EV_ESTABLISHED"];
+	ass abox ass [label="terminate"];
+	ass -> gscon [label="GSCON_EV_ASSIGNMENT_END"];
+	gscon abox gscon [label="ST_ACTIVE"];
 
-	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_ASSIGNMENT_\nWAIT_LCHAN"];
-	bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
-	--- [label="END: lchan FSM decides that it is an lchan for speech"];
-	...;
-	...;
-
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ACTIVE"];
-	bsc_gscon abox bsc_gscon [label="ST_ASSIGNMENT_\nWAIT_COMPLETE\nT10, 6s"];
-	ms <= bsc_gscon [label="RR Assignment"];
-	...;
-	--- [label="On Timeout"];
-	bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
-	bsc_gscon -> bsc_lchan [label="LCHAN_EV_LCHAN_RELEASE"];
-	bsc_gscon box bsc_gscon [label="'forget' all about conn->lchan_for_assignment"];
-	--- [label="IF assignment_created_mgw_endpoint == true"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
-	bsc_gscon note bsc_mgcp [label="If the MGW endpoint didn't exist before the Assignment, release
-		it now. If there was one before this, it is probably still in use by a previous lchan, so
-		keep it in place."];
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-	--- [label="END: 'On Timeout'"];
-	...;
-	ms => bsc_gscon [label="RR Assignment Complete"];
-	bsc_gscon -> bsc_lchan [label="OLD lchan: LCHAN_EV_LCHAN_RELEASE"];
-	bsc_gscon box bsc_gscon [label="conn->lchan = conn->lchan_for_assignment"];
-	--- [label="IF: chan_mode a speech mode?"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_MDCX_BTS"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_modify()"];
-	bsc_mgcp note bsc_mgcp [label="same mgcp FSM as above, for BTS side"];
-	bsc_mgcp abox bsc_mgcp [label="ST_MDCX_RESP"];
-	bsc_mgcp => mgw_msc [label="MDCX (for BTS)"];
-	...;
-	--- [label="On Timeout"];
-	bsc_gscon -> bsc_lchan [label="LCHAN_EV_RELEASE"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
-	bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
-	bsc_gscon => mgw_msc [label="BSSMAP Clear Request"];
-	--- [label="END: 'On Timeout'"];
-	...;
-	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"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_CRCX_MSC"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
-	bsc_mgcp note bsc_mgcp [label="second mgcp FSM for MSC side"];
-	bsc_mgcp => mgw_msc [label="CRCX (for MSC)"];
-	...;
-	--- [label="On Timeout"];
-	bsc_gscon -> bsc_lchan [label="LCHAN_EV_RELEASE"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
-	bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
-	bsc_gscon => mgw_msc [label="BSSMAP Clear Request"];
-	--- [label="END: 'On Timeout'"];
-	...;
-	bsc_mgcp <= mgw_msc [label="CRCX OK (for MSC)"];
-	bsc_gscon <- bsc_mgcp [label="GSCON_EV_MGW_CRCX_RESP_MSC"];
-	--- [label="END: chan_mode a speech mode?"];
-
-	bsc_gscon => mgw_msc [label="BSSMAP Assignment Complete"];
-
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
 }
diff --git a/doc/handover-inter-bsc-in-fsm.dot b/doc/handover-inter-bsc-in-fsm.dot
new file mode 100644
index 0000000..b52a16d
--- /dev/null
+++ b/doc/handover-inter-bsc-in-fsm.dot
@@ -0,0 +1,42 @@
+digraph G {
+rankdir=TB
+labelloc=t; label="Handover FSM: Inter-BSC Incoming"
+
+	old_bss [label="old BSS",shape=box3d]
+	msc [label="MSC",shape=box3d]
+	ho_in [label="inter-BSC HO Incoming",shape=box]
+	gscon [label="gscon FSM",shape=box3d]
+	lchan [label="lchan FSM",shape=box3d]
+	msc2 [label="msc",shape=box3d]
+	old_bsc2 [label="old BSC",shape=box3d]
+	old_lchan [label="old lchan",shape=box3d]
+	terminate [shape=octagon]
+
+	old_bss -> msc [label="BSSMAP Handover Required",style=dotted]
+	msc -> ho_in [label="BSSMAP Handover Request",style=dotted]
+	ho_in -> gscon [label="GSCON_EV_A_CONN_IND\nBSSMAP Handover Request",style=dotted]
+	gscon -> HO_ST_WAIT_LCHAN_ACTIVE [label="handover_start_inter_bsc_in()",style=dotted]
+	HO_ST_WAIT_LCHAN_ACTIVE -> lchan [label="lchan_activate()\nFOR_HANDOVER",style=dotted]
+	lchan -> HO_ST_WAIT_LCHAN_ACTIVE [label="HO_EV_\nLCHAN_ACTIVE,\n_ERROR",style=dotted,constraint=false]
+	HO_ST_WAIT_LCHAN_ACTIVE -> HO_ST_WAIT_RR_HO_DETECT
+	
+	HO_ST_WAIT_RR_HO_DETECT -> msc2 [label="BSSMAP\nHandover\nAccept\nwith\nRR Handover\nCommand",style=dotted]
+	msc2 -> old_bsc2 -> old_lchan [label="RR Handover\nCommand",style=dotted]
+	old_lchan -> lchan [label="MS moves",style=dotted,constraint=false]
+
+	lchan -> HO_ST_WAIT_RR_HO_DETECT [label="RR Handover\nDetect",style=dotted]
+	HO_ST_WAIT_RR_HO_DETECT -> WAIT_RR_HO_COMPLETE
+
+	lchan -> WAIT_RR_HO_COMPLETE [label="RR Handover\nComplete",style=dotted]
+	WAIT_RR_HO_COMPLETE -> WAIT_LCHAN_ESTABLISHED
+	lchan -> WAIT_LCHAN_ESTABLISHED [label="HO_EV_LCHAN_\nESTABLISHED",style=dotted]
+
+	WAIT_LCHAN_ESTABLISHED -> terminate [label="non-TCH"]
+	WAIT_LCHAN_ESTABLISHED -> WAIT_MGW_ENDPOINT_TO_MSC
+	WAIT_MGW_ENDPOINT_TO_MSC -> terminate [label="handover_end()"]
+	terminate -> msc2 [label="BSSMAP Handover\nComplete\n/ Failure",style=dotted,constraint=false]
+
+	err [label="on error",shape=box,style=dashed]
+	err -> terminate [style=dashed]
+
+}
diff --git a/doc/handover-inter-bsc-in.msc b/doc/handover-inter-bsc-in.msc
new file mode 100644
index 0000000..9534f90
--- /dev/null
+++ b/doc/handover-inter-bsc-in.msc
@@ -0,0 +1,74 @@
+msc {
+	hscale=2;
+	ms [label="MS/BTS"], lchan[label="BSC lchan FSM"], ho[label="BSC Handover FSM"],
+	gscon[label="BSC conn FSM"], msc_[label="MSC"];
+
+	ms note msc_ [label="inter-BSC Handover Incoming"];
+
+	gscon <= msc_ [label="N-Connect: BSSMAP Handover Request"];
+	gscon box gscon [label="bsc_subscr_con_allocate()"];
+	gscon abox gscon [label="ST_INIT"];
+	gscon -> gscon [label="GSCON_EV_A_CONN_IND"];
+	ho <- gscon [label="handover_start_inter_bsc_in()"];
+
+	ho abox ho [label="allocate\nHO_ST_NOT_STARTED"];
+	ho box ho [label="lchan_select_by_chan_mode()"];
+	ho abox ho [label="HO_ST_WAIT_\nLCHAN_ACTIVE"];
+	lchan <- ho [label="lchan_activate(FOR_HANDOVER)"];
+	lchan rbox lchan [label="(most details omitted, see lchan_fsm diagrams)"];
+
+	...;
+	...;
+	--- [label="On any error or timeout"];
+	ho box ho [label="handover_end(fail)"];
+	ho -> gscon [label="GSCON_EV_HANDOVER_END"];
+	gscon note msc_ [label="There is no specific BSSMAP Handover Request NACK message."];
+	gscon => msc_ [label="BSSMAP Clear Request"];
+	gscon abox gscon [label="ST_CLEARING"];
+	gscon rbox msc_ [label="the usual disconnect dance"];
+	--- [label="END: 'On any error or timeout'"];
+	...;
+	...;
+
+	lchan abox lchan [label="LCHAN_ST_WAIT_\nACTIV_ACK"];
+	ms <= lchan [label="RSL Chan Activ"];
+	...;
+	ms => lchan [label="RSL Chan Activ ACK"];
+	lchan -> ho [label="HO_EV_LCHAN_ACTIVE"];
+	ho abox ho [label="HO_ST_WAIT_\nRR_HO_DETECT"];
+	ho => msc_ [label="BSSMAP Handover Request Acknowledge\nwith RR Handover Command"];
+
+	...;
+
+	ms => ho [label="RR Handover Detect\nHO_EV_RR_HO_DETECT"];
+	ho => msc_ [label="BSSMAP Handover Detect"];
+	ho abox ho [label="HO_ST_WAIT_\nRR_HO_COMPLETE"];
+
+	...;
+	lchan note ho [label="The lchan FSM will continue with RSL and RTP while the HO FSM waits.
+		HO_EV_LCHAN_ESTABLISHED means that both RSL and RTP are established.
+		Usually, RTP will be done first, and the HO_EV_LCHAN_ESTABLISHED may be
+		received even before HO_EV_RR_HO_COMPLETE.
+		ho_fsm_wait_lchan_established_onenter() decides whether to wait or not."];
+	...;
+	ms => lchan [label="RSL EST IND"];
+	lchan -> ho [label="HO_EV_LCHAN_ESTABLISHED",ID="(may come as early as this, or...)"];
+	ms => ho [label="RR Handover Complete (from EST IND)\n HO_EV_RR_HO_COMPLETE"];
+	ho abox ho [label="HO_ST_WAIT_\nLCHAN_ESTABLISHED"];
+	...;
+	lchan rbox lchan [label="when lchan FSM is done with setting up RTP"];
+	lchan -> ho [label="HO_EV_LCHAN_ESTABLISHED",ID="(...may come only now)"];
+	ho abox ho [label="HO_ST_WAIT_\nMGW_ENDPOINT_TO_MSC"];
+	ho -> gscon [label="gscon_connect_mgw_to_msc()"];
+	...;
+	ho <- gscon [label="HO_EV_MSC_MGW_OK"];
+	ho box ho [label="handover_end(OK)"];
+	ho => msc_ [label="BSSMAP Handover Complete"];
+
+	ho -> gscon [label="gscon_change_primary_lchan()"];
+	lchan <- gscon [label="LCHAN_RTP_EV_ESTABLISHED"];
+	ho -> gscon [label="GSCON_EV_HANDOVER_END"];
+	gscon abox gscon [label="ST_ACTIVE"];
+	ho box ho [label="detach from parent to not fire another meaningless GSCON_EV_HANDOVER_END"];
+	ho abox ho [label="terminate"];
+}
diff --git a/doc/handover-inter-bsc-mo.msc b/doc/handover-inter-bsc-mo.msc
deleted file mode 100644
index 9aff7a7..0000000
--- a/doc/handover-inter-bsc-mo.msc
+++ /dev/null
@@ -1,37 +0,0 @@
-msc {
-	hscale=2;
-	ms [label="MS via BTS"], bsc_lchan[label="BSC lchan FSM"], bsc_gscon[label="BSC conn FSM"],
-	msc_[label="MSC"];
-
-	ms note msc_ [label="inter-BSC Handover to another BSS"];
-
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-	bsc_gscon box bsc_gscon [label="bsc_handover_start(): init conn->ho"];
-	bsc_gscon -> bsc_gscon [label="GSCON_EV_HO_START (inter-BSC MO)"];
-	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MO_\nWAIT_HO_CMD\nT7"];
-	bsc_gscon => msc_ [label="BSSMAP Handover Required"];
-	...;
-	--- [label="On Timeout"];
-	ms note bsc_gscon [label="MS happily continues on the old lchan."];
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-	bsc_gscon box bsc_gscon [label="handover_end(fail)"];
-	--- [label="END: 'On Timeout'"];
-	...;
-	bsc_gscon <= msc_ [label="BSSMAP Handover Command"];
-	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MO_\nWAIT_CLEAR_CMD\nT8"];
-	ms <= bsc_gscon [label="RR Handover Command"];
-	...;
-	--- [label="On Timeout"];
-	ms note bsc_gscon [label="MS happily continues on the old lchan."];
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-	bsc_gscon box bsc_gscon [label="handover_end(fail)"];
-	--- [label="END: 'On Timeout'"];
-	...;
-	msc_ note msc_ [label="Remote BSS reported Handover Complete to the MSC, this connection has been
-		superseded."];
-	bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
-	bsc_gscon abox bsc_gscon [label="ST_CLEARING"];
-	bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
-	bsc_lchan <- bsc_gscon [label="LCHAN_EV_RELEASE"];
-	ms <=> bsc_lchan [label="release procedure (async)"];
-}
diff --git a/doc/handover-inter-bsc-mt.msc b/doc/handover-inter-bsc-mt.msc
deleted file mode 100644
index 88a52da..0000000
--- a/doc/handover-inter-bsc-mt.msc
+++ /dev/null
@@ -1,154 +0,0 @@
-msc {
-	hscale=3;
-	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_msc [label="inter-BSC Handover, from remote BSS"];
-
-	bsc_gscon <= mgw_msc [label="N-Connect: BSSMAP Handover Request"];
-	bsc_gscon box bsc_gscon [label="bsc_subscr_con_allocate()"];
-	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_LCHAN"];
-	bsc_gscon box bsc_gscon [label="lchan_select_by_chan_mode()"];
-	bsc_lchan <- bsc_gscon [label="lchan_activate(lchan, FOR_HANDOVER)"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_TS_READY"];
-	...;
-	--- [label="on no lchan, lchan FSM error or timeout"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
-	bsc_gscon box bsc_gscon [label="handover_end(fail)"];
-	bsc_gscon => mgw_msc [label="BSSMAP Handover Failure"];
-	ms note bsc_gscon [label="MS happily continues on the old lchan."];
-	--- [label="END: 'on error'"];
-	...;
-
-	--- [label="IF lchan FSM decides that it is an lchan for speech"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_MGW_ENDPOINT_AVAILABLE"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_ENSURE_MGW_ENDPOINT"];
-	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 -> bsc_mgcp [label="mgcp_conn_delete()"];
-	bsc_gscon box bsc_gscon [label="handover_end(fail)"];
-	bsc_gscon => mgw_msc [label="BSSMAP Handover Failure"];
-	ms note bsc_gscon [label="MS happily continues on the old lchan."];
-	--- [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 -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_ACTIV_ACK"];
-	bsc_gscon note bsc_gscon [label="MSC-side CRCX needs from Handover Required the RTP IP address
-		and port of the MSC's MGW; from MGW CRCX ACK (BTS) the conn->user_plane.mgw_endpoint; The
-		Call-ID, which we actually derive from the SCCP connection ID"];
-	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_CRCX_MSC"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
-	bsc_mgcp note bsc_mgcp [label="second mgcp FSM for MSC side"];
-	bsc_mgcp => mgw_msc [label="CRCX (for MSC)"];
-	...;
-	--- [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_MSC"];
-	bsc_gscon note bsc_gscon [label="GSCON_EV_MGW_FAIL_MSC is handled by the conn FSM allstate
-		handler. It sets conn->user_plane.fi_msc = NULL."];
-	bsc_gscon -> bsc_lchan [label="LCHAN_EV_RELEASE"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete() (FSM for BTS)"];
-	bsc_gscon box bsc_gscon [label="handover_end(fail)"];
-	bsc_gscon => mgw_msc [label="BSSMAP Handover Failure"];
-	ms note bsc_gscon [label="MS happily continues on the old lchan."];
-	--- [label="END: 'On Timeout'"];
-	...;
-	bsc_mgcp <= mgw_msc [label="CRCX OK (for MSC)"];
-	bsc_gscon <- bsc_mgcp [label="GSCON_EV_MGW_CRCX_RESP_MSC"];
-	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_LCHAN"];
-	--- [label="END: chan_mode a speech mode?"];
-	--- [label="END: lchan FSM decides that it is an lchan for speech"];
-	...;
-	...;
-
-	bsc_lchan note bsc_lchan [label="TODO: when does the MS send RLL Establish Ind? I guess like
-		this:"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_RLL_ESTABLISH"];
-	ms => bsc_lchan [label="RLL Establish Ind"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ACTIVE"];
-	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_\nWAIT_HO_ACCEPT\nsanity timer?"];
-	bsc_gscon box bsc_gscon [label="Compose RR Handover Command"];
-	bsc_gscon => mgw_msc [label="BSSMAP Handover Request Acknowledge"];
-	mgw_msc note mgw_msc [label="MSC forwards the RR HO Cmd to the remote BSS"];
-
-	...;
-	--- [label="On timeout"];
-	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)"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
-	bsc_gscon => mgw_msc [label="BSSMAP Clear Request"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
-	ms note bsc_gscon [label="MS happily continues on the old lchan."];
-	--- [label="END: On timeout"];
-	...;
-	ms => bsc_gscon [label="RR Handover Accept"];
-	bsc_gscon => mgw_msc [label="BSSMAP Handover Detect"];
-	mgw_msc note mgw_msc [label="MSC switches call to new path"];
-	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_SABM\nT3105"];
-	...;
-	ms => bsc_gscon [label="SABM"];
-	bsc_lchan note bsc_lchan [label="SABM: Layer 2 message containing ?"];
-	bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_\nWAIT_MDCX_BTS\nT?"];
-	bsc_lchan note bsc_lchan [label="TODO: what is UA?"];
-	ms <= bsc_gscon [label="RR UA"];
-	bsc_gscon note bsc_gscon [label="TODO: at what point do we know the information needed for BTS
-		MDCX?"];
-	bsc_gscon -> bsc_mgcp [label="mgcp_conn_modify()"];
-	bsc_mgcp abox bsc_mgcp [label="ST_MDCX_RESP"];
-	bsc_mgcp => mgw_msc [label="MDCX (for BTS)"];
-	...;
-	--- [label="Should the Handover Complete arrive early"];
-	ms => bsc_gscon [label="RR Handover Complete"];
-	bsc_gscon box bsc_gscon [label="handover_complete_received = true"];
-	---;
-	...;
-	--- [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()"];
-	--- [label="END: On timeout of the mgcp FSM"];
-	...;
-	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_MT_WAIT_HO_COMPL\nT?"];
-	--- [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 => mgw_msc [label="BSSMAP Handover Complete"];
-	bsc_gscon note bsc_gscon [label="handover_end(success), conn->ho = NULL"];
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-}
diff --git a/doc/handover-inter-bsc-out-fsm.dot b/doc/handover-inter-bsc-out-fsm.dot
new file mode 100644
index 0000000..9661b6f
--- /dev/null
+++ b/doc/handover-inter-bsc-out-fsm.dot
@@ -0,0 +1,27 @@
+digraph G {
+rankdir=TB
+labelloc=t; label="Handover FSM: Inter-BSC Outgoing"
+
+	invisible [style=invisible]
+	invisible -> ho_out [label="Measurement Report\nincluding neighbor\nBSS ARFCN",style=dotted]
+        ho_out [label="inter-BSC HO Outgoing",shape=box]
+        msc [label="MSC",shape=box3d]
+	new_bsc [label="new BSC",shape=box3d]
+	lchan [label="lchan",shape=box3d]
+        terminate [shape=octagon]
+
+	ho_out -> HO_OUT_ST_WAIT_HO_COMMAND [label="handover_start()"]
+	HO_OUT_ST_WAIT_HO_COMMAND -> msc [label="BSSMAP Handover\nRequired",style=dotted]
+	msc -> new_bsc [label="BSSMAP Handover\nRequest",style=dotted]
+	new_bsc -> msc [label="BSSMAP Handover\nRequest Ack",style=dotted]
+	msc -> HO_OUT_ST_WAIT_HO_COMMAND [label="BSSMAP Handover\nCommand",style=dotted]
+
+	HO_OUT_ST_WAIT_HO_COMMAND -> lchan [label="RR Handover\nCommand\nfrom new BSC",style=dotted]
+
+	HO_OUT_ST_WAIT_HO_COMMAND -> HO_OUT_ST_WAIT_CLEAR
+	msc -> HO_OUT_ST_WAIT_CLEAR [label="BSSMAP\nClear\nCommand",style=dotted]
+
+	HO_OUT_ST_WAIT_CLEAR -> terminate
+
+
+}
diff --git a/doc/handover-inter-bsc-out.msc b/doc/handover-inter-bsc-out.msc
new file mode 100644
index 0000000..733b4da
--- /dev/null
+++ b/doc/handover-inter-bsc-out.msc
@@ -0,0 +1,47 @@
+msc {
+	hscale=2;
+	ms [label="MS/BTS"], ho[label="BSC Handover FSM"], gscon[label="BSC conn FSM"], msc_[label="MSC"];
+
+	ms note msc_ [label="inter-BSC Handover to another BSS"];
+
+	gscon abox gscon [label="ST_ACTIVE"];
+
+	ms => ho [label="Measurement Report"];
+	ho box ho [label="Handover Decision"];
+	ho box ho [label="handover_request\n(struct handover_out_req)"];
+	ho note gscon [label="To make sure the conn FSM permits a handover, trigger an event:"];
+	ho -> gscon [label="GSCON_EV_HANDOVER_START\ndata=handover_out_req"];
+	gscon abox gscon [label="ST_HANDOVER"];
+	ho <- gscon [label="handover_start\n(handover_out_req)"];
+	ho box ho [label="handover_start_inter_bsc_out()"];
+	ho => msc_ [label="BSSMAP Handover Required"];
+	ho abox ho [label="HO_OUT_ST_WAIT_HO_COMMAND"];
+	...;
+	...;
+	--- [label="On Timeout"];
+	ho box ho [label="handover_end(fail)"];
+	ho -> gscon [label="GSCON_EV_HANDOVER_END"];
+	gscon abox gscon [label="ST_ACTIVE"];
+	ms note gscon [label="MS happily continues on the old lchan."];
+	--- [label="END: 'On Timeout'"];
+	...;
+	...;
+	ho <= msc_ [label="BSSMAP Handover Command\n HO_OUT_EV_BSSMAP_HO_COMMAND"];
+	ms <= ho [label="Forward L3 Info (RR Handover Command from new BSS)"];
+	ho abox ho [label="HO_OUT_ST_WAIT_CLEAR"];
+	...;
+	gscon abox gscon [label="ST_HANDOVER_MO_\nWAIT_CLEAR_CMD\nT8"];
+	ms <= gscon [label="RR Handover Command"];
+	...;
+	ho rbox gscon [label="On Timeout: same as above"];
+	...;
+	msc_ note msc_ [label="Remote BSS reported Handover Complete to the MSC,
+	     this connection has been superseded."];
+	gscon <= msc_ [label="BSSMAP Clear Command\n GSCON_EV_A_CLEAR_CMD"];
+	gscon abox gscon [label="ST_CLEARING"];
+	gscon => msc_ [label="BSSMAP Clear Complete"];
+	...;
+	gscon <= msc_ [label="DISC IND\n GSCON_EV_A_DISC_IND"];
+	ho abox ho [label="terminate\n(child of conn FSM)"];
+	gscon abox gscon [label="terminate"];
+}
diff --git a/doc/handover-intra-bsc-fsm.dot b/doc/handover-intra-bsc-fsm.dot
new file mode 100644
index 0000000..7cb0d3c
--- /dev/null
+++ b/doc/handover-intra-bsc-fsm.dot
@@ -0,0 +1,30 @@
+digraph G {
+rankdir=TB
+labelloc=t; label="Handover FSM: Intra-BSC"
+
+        lchan [label="lchan FSM",shape=box3d]
+        intra [label="intra-BSC HO",shape=box]
+        old_lchan [label="old lchan",shape=box3d]
+	terminate [shape=octagon]
+
+	invisible [style="invisible"]
+	invisible -> intra [label="Measurement Report",style=dotted]
+	invisible -> old_lchan [style=invisible,arrowhead=none]
+
+	intra -> WAIT_LCHAN_ACTIVE [label="handover_start()",style=dotted]
+        WAIT_LCHAN_ACTIVE -> lchan [label="lchan_activate(FOR_HANDOVER)",style=dotted]
+	lchan -> WAIT_LCHAN_ACTIVE [label="HO_EV_\nLCHAN_\nACTIVE,ERROR",style=dotted,constraint=false]
+        WAIT_LCHAN_ACTIVE -> WAIT_RR_HO_DETECT
+        WAIT_RR_HO_DETECT -> old_lchan [label="RR Handover\nCommand",style=dotted,constraint=false]
+	
+	lchan -> WAIT_RR_HO_DETECT [label="RR Handover\nDetect",style=dotted]
+	WAIT_RR_HO_DETECT -> WAIT_RR_HO_COMPLETE
+
+	lchan -> WAIT_RR_HO_COMPLETE [label="RR Handover\nComplete",style=dotted]
+	WAIT_RR_HO_COMPLETE -> WAIT_LCHAN_ESTABLISHED
+	lchan -> WAIT_LCHAN_ESTABLISHED [label="HO_EV_LCHAN_\nESTABLISHED",style=dotted]
+
+	WAIT_LCHAN_ESTABLISHED -> terminate [label="non-TCH"]
+	WAIT_LCHAN_ESTABLISHED -> WAIT_MGW_ENDPOINT_TO_MSC
+	WAIT_MGW_ENDPOINT_TO_MSC -> terminate [label="handover_end()"]
+}
diff --git a/doc/handover.msc b/doc/handover.msc
index 7529de6..1a2580a 100644
--- a/doc/handover.msc
+++ b/doc/handover.msc
@@ -1,123 +1,82 @@
 # Handover between cells, intra-BSC
 msc {
-	hscale=3;
-	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"];
+	hscale=2;
+	ms [label="MS via BTS"], lchan[label="BSC lchan FSM"], ho[label="BSC Handover FSM"],
+	gscon[label="BSC conn FSM"], msc_[label="MSC"];
 
-	ms note mgw_msc [label="intra-BSC Handover sequence"];
+	ms note msc_ [label="intra-BSC Handover"];
 
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-	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)"];
+	gscon abox gscon [label="ST_ACTIVE"];
+
+	ms => ho [label="Measurement Report"];
+	ho box ho [label="Handover Decision"];
+	ho box ho [label="handover_request\n(struct handover_out_req)"];
+	ho note gscon [label="To make sure the conn FSM permits a handover, trigger an event:"];
+	ho -> gscon [label="GSCON_EV_HANDOVER_START\ndata=handover_out_req"];
+	gscon abox gscon [label="ST_HANDOVER"];
+	ho <- gscon [label="handover_start\n(handover_out_req)"];
+	ho box ho [label="handover_start_intra_bsc()"];
+	ho abox ho [label="allocate\nHO_ST_NOT_STARTED"];
+
 	...;
-	--- [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'"];
+	...;
+	--- [label="On any error or timeout"];
+	ho box ho [label="handover_end(fail)"];
+	ho -> gscon [label="GSCON_EV_HANDOVER_END"];
+	gscon abox gscon [label="ST_ACTIVE"];
+	ms note gscon [label="MS happily continues on the old lchan."];
+	--- [label="END: 'On any error or timeout'"];
 	...;
 	...;
 
-	--- [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()"];
-	---;
-	ms note bsc_gscon [label="MS happily continues on the old lchan."];
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-	--- [label="END: 'On Timeout'"];
-	...;
+	ho box ho [label="lchan_select_by_type()"];
+	ho abox ho [label="HO_ST_WAIT_\nLCHAN_ACTIVE"];
+	lchan <- ho [label="lchan_activate(FOR_HANDOVER)"];
+	lchan rbox lchan [label="(most details omitted, see lchan_fsm diagrams)"];
 
-	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"];
+	...;
+	...;
+	--- [label="On lchan error or timeout"];
+	lchan -> ho [label="HO_EV_LCHAN_ERROR"];
+	ho rbox gscon [label="same as above"];
+	--- [label="END: 'On lchan error or timeout'"];
 	...;
 	...;
 
-	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"];
-
+	lchan abox lchan [label="LCHAN_ST_WAIT_ACTIV_ACK"];
+	ms <= lchan [label="RSL Chan Activ"];
 	...;
-	--- [label="On timeout"];
-	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 => lchan [label="RSL Chan Activ ACK"];
+	lchan -> ho [label="HO_EV_LCHAN_ACTIVE"];
+	ho abox ho [label="HO_ST_WAIT_\nRR_HO_DETECT"];
 	...;
-	ms => bsc_gscon [label="RR Handover Detect"];
-
-	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 abox bsc_mgcp [label="ST_MDCX_RESP"];
-	bsc_mgcp => mgw_msc [label="MDCX (for BTS)"];
+	ms => ho [label="RR Handover Detect\nHO_EV_RR_HO_DETECT"];
+	lchan note ho [label="At this point we should start to switch the MGW over to the new lchan.
+		But this is not implemented yet, as was not before introducing these FSMs."];
+	ho abox ho [label="HO_ST_WAIT_\nRR_HO_COMPLETE"];
 	...;
-	--- [label="Should the Handover Complete arrive early"];
-	ms => bsc_gscon [label="RR Handover Complete"];
-	bsc_gscon box bsc_gscon [label="handover_complete_received = true"];
-	---;
+	lchan note ho [label="The lchan FSM will continue with RSL and RTP while the HO FSM waits.
+		HO_EV_LCHAN_ESTABLISHED means that both RSL and RTP are established.
+		Usually, RTP will be done first, and the HO_EV_LCHAN_ESTABLISHED may be
+		received even before HO_EV_RR_HO_COMPLETE.
+		ho_fsm_wait_lchan_established_onenter() decides whether to wait or not."];
 	...;
-	--- [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()"];
+	ms => lchan [label="RSL EST IND"];
+	lchan -> ho [label="HO_EV_LCHAN_ESTABLISHED",ID="(may come as early as this, or...)"];
+	ms => ho [label="RR Handover Complete (from EST IND)\n HO_EV_RR_HO_COMPLETE"];
+	ho abox ho [label="HO_ST_WAIT_\nLCHAN_ESTABLISHED"];
 	...;
-	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()"];
-	---;
+	lchan rbox lchan [label="when lchan FSM is done with setting up RTP"];
+	lchan -> ho [label="HO_EV_LCHAN_ESTABLISHED",ID="(...may come only now)"];
+	ho abox ho [label="HO_ST_WAIT_\nMGW_ENDPOINT_TO_MSC"];
+	ho -> gscon [label="gscon_connect_mgw_to_msc()"];
 	...;
-	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"];
+	ho <- gscon [label="HO_EV_MSC_MGW_OK"];
+	ho box ho [label="handover_end(OK)"];
+	ho -> gscon [label="gscon_change_primary_lchan()"];
+	lchan <- gscon [label="LCHAN_RTP_EV_ESTABLISHED"];
+	ho -> gscon [label="GSCON_EV_HANDOVER_END"];
+	gscon abox gscon [label="ST_ACTIVE"];
+	ho box ho [label="detach from parent to not fire another meaningless GSCON_EV_HANDOVER_END"];
+	ho abox ho [label="terminate"];
 }
diff --git a/doc/lchan-fsm.dot b/doc/lchan-fsm.dot
index dbb283c..b726b0c 100644
--- a/doc/lchan-fsm.dot
+++ b/doc/lchan-fsm.dot
@@ -1,38 +1,22 @@
 digraph G {
-rankdir=TB;
+rankdir=TB
+labelloc=t; label="lchan FSM"
 	
 	invisible [style="invisible"]
 	UNUSED [penwidth=3.0]
-	WAIT_TS_READY
-	WAIT_MGW_ENDPOINT_AVAILABLE
-	WAIT_ACTIV_ACK
-	WAIT_IPACC_CRCX_ACK
-	WAIT_IPACC_MDCX_ACK
-	WAIT_RLL_ESTABLISH
-	ACTIVE [penwidth=3.0]
-	WAIT_SAPIS_RELEASED
-	WAIT_BEFORE_RF_RELEASE
-	WAIT_RF_RELEASE_ACK
-	WAIT_AFTER_ERROR
-	BORKEN
+	ESTABLISHED [penwidth=3.0]
 	
-	ts [label="timeslot FSM",shape=box3d];
-	gscon [label="conn FSM",shape=box3d];
+	ts [label="timeslot FSM",shape=box3d]
+	rtp [label="lchan_rtp\nFSM",shape=box3d]
 
 	UNUSED -> WAIT_TS_READY [label="lchan_allocate()"]
 	WAIT_TS_READY -> WAIT_ACTIV_ACK
-	WAIT_ACTIV_ACK -> WAIT_RLL_ESTABLISH
-	WAIT_RLL_ESTABLISH -> WAIT_MGW_ENDPOINT_AVAILABLE [label="TCH"]
-	WAIT_MGW_ENDPOINT_AVAILABLE -> WAIT_IPACC_CRCX_ACK [label="IPACC BTS"]
-	WAIT_MGW_ENDPOINT_AVAILABLE -> ACTIVE
-	WAIT_IPACC_CRCX_ACK -> WAIT_IPACC_MDCX_ACK
-	WAIT_IPACC_MDCX_ACK -> ACTIVE
-	WAIT_RLL_ESTABLISH -> ACTIVE [label="non-TCH"];
-	WAIT_RLL_ESTABLISH -> WAIT_RF_RELEASE_ACK [label="timeout",style=dashed,constraint=false]
+	WAIT_ACTIV_ACK -> WAIT_RLL_RTP_ESTABLISH
+	WAIT_RLL_RTP_ESTABLISH -> ESTABLISHED
 
-	ACTIVE -> WAIT_SAPIS_RELEASED [label="LCHAN_EV_\nRELEASE"]
-	WAIT_SAPIS_RELEASED -> WAIT_BEFORE_RF_RELEASE
-	WAIT_SAPIS_RELEASED -> WAIT_RF_RELEASE_ACK [label="timeout",style=dashed,constraint=false]
+	ESTABLISHED -> WAIT_RLL_RTP_RELEASED [label="LCHAN_EV_\nRELEASE"]
+	WAIT_RLL_RTP_RELEASED -> WAIT_BEFORE_RF_RELEASE
+	WAIT_RLL_RTP_RELEASED -> WAIT_RF_RELEASE_ACK [label="timeout",style=dashed,constraint=false]
 
 	WAIT_BEFORE_RF_RELEASE -> WAIT_RF_RELEASE_ACK [label="T3111"]
 	WAIT_RF_RELEASE_ACK -> UNUSED
@@ -43,11 +27,15 @@
 	UNUSED -> ts [label="TS_EV_\nLCHAN_\nUNUSED",style=dotted,penwidth=3]
 	ts -> WAIT_TS_READY [label="LCHAN_EV_\nTS_READY",style=dotted]
 
+	WAIT_TS_READY -> rtp [label="TCH",style=dotted]
+
 	WAIT_TS_READY -> UNUSED [label="error/timeout",style=dashed,constraint=false]
 	{WAIT_ACTIV_ACK,WAIT_RF_RELEASE_ACK} -> BORKEN [label="error/timeout",style=dashed]
-	{WAIT_MGW_ENDPOINT_AVAILABLE,WAIT_IPACC_CRCX_ACK,WAIT_IPACC_MDCX_ACK} -> WAIT_SAPIS_RELEASED [label=error,style=dashed]
+	BORKEN -> WAIT_AFTER_ERROR [label="late RF Release ACK"]
+	WAIT_RLL_RTP_ESTABLISH -> WAIT_RLL_RTP_RELEASED [label=error,style=dashed]
 
-	WAIT_TS_READY -> gscon [label="GSCON_EV_\nENSURE_\nMGW_ENDPOINT",style=dotted]
-	gscon -> WAIT_MGW_ENDPOINT_AVAILABLE [label="LCHAN_EV_\nMGW_ENDPOINT_\n{AVAILABLE,ERROR}",style=dotted]
+	WAIT_ACTIV_ACK -> rtp [label="LCHAN_RTP_EV_LCHAN_READY",style=dotted]
+	rtp -> WAIT_RLL_RTP_ESTABLISH [label="LCHAN_EV_RTP_READY",style=dotted]
+	rtp -> ESTABLISHED [label="LCHAN_EV_RTP_RELEASED",style=dotted]
 
 }
diff --git a/doc/lchan-release.msc b/doc/lchan-release.msc
deleted file mode 100644
index 017c9cf..0000000
--- a/doc/lchan-release.msc
+++ /dev/null
@@ -1,83 +0,0 @@
-msc {
-	hscale=2;
-	ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_lchan[label="BSC lchan FSM"],
-	bsc_gscon[label="BSC conn FSM"], msc_[label="MSC"];
-
-	ms note bsc_gscon [label="various lchan release scenarios"];
-	
-	ms rbox msc_ [label="MSC releases"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
-	bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
-	bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
-	bsc_gscon abox bsc_gscon [label="ST_CLEARING"];
-	bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
-	bsc_gscon -> bsc_lchan [label="LCHAN_EV_RELEASE"];
-	--- [label="IF SAPIs besides SAPI[0] are active"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nSAPIS_RELEASED\nT3109"];
-	bts <= bsc_lchan [label="RSL Release Request (Local End)..."];
-	bts <= bsc_lchan [label="...for each SAPI, except link_id=0"];
-	ms <= bsc_lchan [label="RR Channel Release"];
-	bts <= bsc_lchan [label="RSL Deactivate SACCH",ID="if appropriate pchan"];
-	...;
-	bts => bsc_lchan [label="RSL Release ACKs"];
-	--- [label="END: SAPIs besides SAPI[0] are active"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_FORGET_LCHAN"];
-	bsc_gscon note bsc_gscon [label="has already forgotten the lchan above."];
-	...;
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\n4s"];
-	bts <= bsc_lchan [label="RSL RF Channel Release"];
-	...;
-	bts => bsc_lchan [label="RSL RF Channel Release ACK"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
-	...;
-	...;
-
-	ms rbox msc_ [label="BSC releases, outside of conn FSM's flow"];
-	bsc -> bsc_lchan [label="LCHAN_EV_RELEASE"];
-	--- [label="IF SAPIs besides SAPI[0] are active"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nSAPIS_RELEASED\nT3109"];
-	bts <= bsc_lchan [label="RSL Release Request (Local End)..."];
-	bts <= bsc_lchan [label="...for each SAPI, except link_id=0"];
-	ms <= bsc_lchan [label="RR Channel Release",ID="if conn is present"];
-	bts <= bsc_lchan [label="RSL Deactivate SACCH",ID="if appropriate pchan"];
-	...;
-	bts => bsc_lchan [label="RSL Release ACKs"];
-	--- [label="END: SAPIs besides SAPI[0] are active"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_FORGET_LCHAN"];
-	bsc_gscon note bsc_gscon [label="conn FSM notices that its primary lchan is gone"];
-	bsc_gscon => msc_ [label="BSSMAP Clear Request"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
-	...;
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\n4s"];
-	bts <= bsc_lchan [label="RSL RF Channel Release"];
-	...;
-	bts => bsc_lchan [label="RSL RF Channel Release ACK"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
-	...;
-	bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
-	bsc_gscon abox bsc_gscon [label="ST_CLEARING"];
-	bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
-	...;
-	...;
-
-	ms rbox msc_ [label="MS releases"];
-	ms => bts [label="DISC"];
-	bts => bsc_lchan [label="RLL Release Ind..."];
-	bts => bsc_lchan [label="...for each SAPI"];
-	bsc_lchan note bsc_lchan [label="The lchan FSM notices when all SAPIs have been released"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
-	...;
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\n4s"];
-	bts <= bsc_lchan [label="RSL RF Channel Release"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_FORGET_LCHAN"];
-	bsc_gscon note bsc_gscon [label="conn FSM notices that its primary lchan is gone"];
-	bsc_gscon => msc_ [label="BSSMAP Clear Request"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
-	...;
-	bts => bsc_lchan [label="RSL RF Channel Release ACK"];
-	...;
-	bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
-	bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
-}
diff --git a/doc/lchan-rtp-fsm.dot b/doc/lchan-rtp-fsm.dot
new file mode 100644
index 0000000..d5df643
--- /dev/null
+++ b/doc/lchan-rtp-fsm.dot
@@ -0,0 +1,44 @@
+digraph G {
+rankdir=TB
+labelloc=t; label="lchan RTP FSM"
+	
+	lchan [label="lchan\nFSM",shape=box3d]
+	lchan2 [label="lchan\nFSM",shape=box3d]
+	ho_as [label="Handover or Assignment FSM",shape=box3d]
+	invisible [style=invisible]
+	ho [label="Handover FSM",shape=box3d]
+	mgwep [label="mgw endpoint\nFSM",shape=box3d]
+	start [label="lchan_rtp_fsm_start()",shape=box]
+	WAIT_READY_TO_SWITCH_RTP [label="WAIT_READY_TO_SWITCH_RTP\nonly if wait_before_switching_rtp"]
+	terminate [shape=octagon]
+
+	lchan -> start [style=dashed]
+	start -> WAIT_MGW_ENDPOINT_AVAILABLE
+	start -> WAIT_LCHAN_READY [label="re-use existing\nendpoint CI"]
+
+	WAIT_MGW_ENDPOINT_AVAILABLE -> mgwep [label="gscon_ensure_mgw_endpoint()\nand CRCX to-BTS",style=dashed]
+	mgwep -> WAIT_MGW_ENDPOINT_AVAILABLE [label="LCHAN_RTP_EV_\nMGW_ENDPOINT_\n{AVAILABLE,ERROR}",style=dashed]
+	WAIT_MGW_ENDPOINT_AVAILABLE -> WAIT_LCHAN_READY
+
+	lchan -> WAIT_LCHAN_READY [label="LCHAN_RTP_EV_LCHAN_READY",style=dashed]
+	WAIT_LCHAN_READY -> WAIT_IPACC_CRCX_ACK [label="IPACC BTS"]
+	WAIT_LCHAN_READY -> WAIT_READY_TO_SWITCH_RTP
+	WAIT_IPACC_CRCX_ACK -> WAIT_IPACC_MDCX_ACK
+	WAIT_IPACC_MDCX_ACK -> WAIT_READY_TO_SWITCH_RTP
+	invisible -> ho [label="HO DETECT",style=dashed]
+	ho -> WAIT_READY_TO_SWITCH_RTP [label="LCHAN_RTP_EV_READY_TO_SWITCH",style=dashed]
+	WAIT_READY_TO_SWITCH_RTP -> WAIT_MGW_ENDPOINT_CONFIGURED
+	WAIT_MGW_ENDPOINT_CONFIGURED -> mgwep [label="MDCX",style=dashed]
+	mgwep -> WAIT_MGW_ENDPOINT_CONFIGURED [label="LCHAN_RTP_EV_\nMGW_ENDPOINT_\nCONFIGURED",style=dashed]
+	WAIT_MGW_ENDPOINT_CONFIGURED -> RTP_READY
+	RTP_READY -> lchan2 [label="LCHAN_EV_\nRTP_READY",style=dashed]
+	RTP_READY -> RTP_ESTABLISHED
+	lchan2 -> RTP_ESTABLISHED [label="LCHAN_RTP_EV_\nRELEASE",style=dashed]
+	RTP_ESTABLISHED -> terminate
+	RTP_READY -> RTP_ROLLBACK
+	RTP_ROLLBACK -> terminate
+	terminate -> lchan2 [label="LCHAN_EV_\nRTP_RELEASED",style=dashed]
+
+	lchan2 -> ho_as [label="XX_EV_LCHAN_\nESTABLISHED",style=dashed]
+	ho_as -> RTP_READY [label="LCHAN_RTP_EV_\n{ESTABLISHED,\nROLLBACK}",style=dashed]
+}
diff --git a/doc/lchan.msc b/doc/lchan.msc
index 9b7d663..e2caa48 100644
--- a/doc/lchan.msc
+++ b/doc/lchan.msc
@@ -1,306 +1,216 @@
 msc {
 	hscale=2;
-	bts [label="MS/BTS"], bsc[label="BSC"], bsc_ts [label="BSC timeslot FSM"],
-	bsc_lchan[label="BSC lchan FSM"], bsc_gscon[label="BSC conn FSM"],
-	mgw_msc[label="MGW/MSC"];
+	ms [label="MS/BTS"], ts [label="BSC timeslot FSM"],
+	lchan[label="BSC lchan FSM"], rtp[label="BSC lchan RTP FSM"],mgwep[label="BSC MGW endpoint FSM"];
 
-	bts box mgw_msc [label="lchan allocation sequence"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
+	ms box mgwep [label="lchan allocation sequence"];
+	lchan abox lchan [label="LCHAN_ST_UNUSED"];
+	...;
+	lchan rbox lchan [label="lchan_activate(activate_info)"];
+	lchan note lchan [label="Dispatching event to make sure the lchan FSM permits activation."];
+	lchan -> lchan [label="LCHAN_EV_ACTIVATE\ndata = activate_info"];
+	lchan abox lchan [label="LCHAN_ST_\nWAIT_TS_READY"];
+	ts <- lchan [label="TS_EV_LCHAN_REQUESTED"];
+	ts rbox ts [label="Most details omitted. See timeslot FSM diagrams."];
+	ts note ts [label="A dyn TS may be in PDCH mode and will asynchronously switch off PDCH first. A
+		non-dynamic TS is ready immediately."];
+	|||;
+	--- [label="IF requires_voice_stream"];
+	lchan -> rtp [label="lchan_rtp_fsm_start()"];
+	rtp abox rtp [label="allocate\n LCHAN_RTP_ST_\nWAIT_MGW_ENDPOINT_\nAVAILABLE"];
+	--- [label="IF no endpoint-CI yet"];
+	rtp box rtp [label="gscon_ensure_mgw_endpoint()"];
+	rtp -> mgwep [label="mgw_endpoint_ci_add(to-BTS)"];
+	rtp -> mgwep [label="CRCX to-BTS"];
+	mgwep rbox mgwep [label="MGCP: CRCX"];
+	...;
+	mgwep rbox mgwep [label="MGCP: CRCX OK"];
+	rtp <- mgwep [label="LCHAN_RTP_EV_MGW_ENDPOINT_AVAILABLE"];
+	rtp note mgwep [label="The CRCX OK has assigned us a new endpoint CI number"];
+	rtp abox rtp [label="LCHAN_RTP_ST_WAIT_LCHAN_READY"];
+	--- [label="END: no endpoint-CI yet"];
+	--- [label="END: requires_voice_stream"];
+	|||;
+	...;
+	ts -> lchan [label="LCHAN_EV_TS_READY"];
+	lchan abox lchan [label="LCHAN_ST_\nWAIT_ACTIV_ACK"];
+	--- [label="IF FOR_MS_CHANNEL_REQUEST"];
+	ms <= lchan [label="RSL Chan Activ (RSL_ACT_INTRA_IMM_ASS)"];
+	--- [label="ELSE: FOR_ASSIGNMENT"];
+	ms <= lchan [label="RSL Chan Activ (RSL_ACT_INTRA_NORM_ASS)"];
+	--- [label="ELSE: FOR_HANDOVER"];
+	ms <= lchan [label="RSL Chan Activ (RSL_ACT_INTER_ASYNC)"];
+	--- [label="END"];
+	...;
+	ms rbox lchan [label="On timeout or Chan Activ NACK, see: 'On any error', 'unrecoverable'"];
+	...;
+	ms => lchan [label="RSL Chan Activ ACK"];
+	lchan box lchan [label="lchan_fsm_post_activ_ack()"];
 
-	bts rbox mgw_msc [label="Channel Request from MS"];
-	bts => bsc [label="RSL Channel Request"];
-	bsc box bsc [label="lchan_select_by_type(chan_type)"];
-	bsc -> bsc_lchan [label="lchan_activate(lchan, FOR_MS_CHANNEL_REQUEST)"];
-	bsc_lchan rbox bsc_lchan [label="Continue at\nlchan_activate()\n"];
+	--- [label="IF FOR_MS_CHANNEL_REQUEST"];
+	ms <= lchan [label="RR Immediate Assignment"];
+	--- [label="ELSE: FOR_ASSIGNMENT"];
+	lchan rbox lchan [label="dispatch\nASSIGNMENT_EV_\nLCHAN_ACTIVE\n(see Assignment FSM diagrams)"];
+	ms <= lchan [label="RR Assignment Command"];
+	--- [label="ELSE: FOR_HANDOVER"];
+	lchan rbox lchan [label="dispatch\nHO_EV_LCHAN_ACTIVE\n(see Handover FSM diagrams)"];
+	--- [label="END"];
+
+
+	lchan abox lchan [label="LCHAN_ST_WAIT_\nRLL_RTP_ESTABLISH\nT3101"];
+	|||;
+	|||;
+	--- [label="IF requires_voice_stream"];
+	lchan -> rtp [label="LCHAN_RTP_EV_LCHAN_READY"];
+	|||;
+	--- [label="IF ip.access style BTS"];
+	rtp abox rtp [label="LCHAN_RTP_ST_WAIT_IPACC_CRCX_ACK"];
+	ms <= rtp [label="IPACC CRCX"];
+	...;
+	ms => rtp [label="IPACC CRCX ACK (BTS RTP port info)"];
+	rtp abox rtp [label="LCHAN_RTP_ST_WAIT_IPACC_MDCX_ACK"];
+	ms <= rtp [label="IPACC MDCX (MGW RTP port info)"];
+	...;
+	ms => rtp [label="IPACC MDCX ACK"];
+	--- [label="END ip.access style BTS"];
+	|||;
+	rtp box rtp [label="lchan_rtp_fsm_switch_rtp()"];
+	|||;
+	--- [label="IF wait_before_switching_rtp"];
+	rtp note rtp [label="During Handover, wait for HO DETECT before redirecting an existing endpoint
+		CI towards the new lchan."];
+	rtp abox rtp [label="LCHAN_RTP_ST_WAIT_READY_TO_SWITCH_RTP"];
+	...;
+	ms => rtp [label="HO DETECT (via Handover FSM)"];
+	--- [label="END: wait_before_switching_rtp"];
+	|||;
+	rtp abox rtp [label="LCHAN_RTP_ST_WAIT_MGW_ENDPOINT_CONFIGURED"];
+	rtp box rtp [label="connect_mgw_endpoint_to_lchan()"];
+	rtp -> mgwep [label="MDCX to-BTS"];
+	mgwep rbox mgwep [label="MGCP: MDCX"];
+	...;
+	mgwep rbox mgwep [label="MGCP: MDCX OK"];
+	rtp <- mgwep [label="LCHAN_RTP_EV_MGW_ENDPOINT_CONFIGURED"];
+	rtp abox rtp [label="LCHAN_RTP_ST_READY"];
+	lchan <- rtp [label="LCHAN_EV_RTP_READY"];
+	rtp note rtp [label="RTP FSM stays ready for Rollback until final establish event"];
+	...;
+	lchan -> rtp [label="LCHAN_RTP_EV_ESTABLISHED\nvia gscon_change_primary_lchan()"];
+	rtp abox rtp [label="LCHAN_RTP_ST_\nESTABLISHED"];
+	--- [label="END: requires_voice_stream"];
 	|||;
 	|||;
 
-	bts rbox mgw_msc [label="Channel Request from BSSMAP Assignment"];
-	bsc_gscon <= mgw_msc [label="BSSMAP Assignment request"];
-	bsc_gscon box bsc_gscon [label="lchan_select_by_chan_mode(chan_mode)"];
-	bsc_lchan <- bsc_gscon [label="lchan_activate(lchan, FOR_ASSIGNMENT)"];
-	bsc_lchan rbox bsc_lchan [label="Continue at\nlchan_activate()\n"];
-	|||;
-	|||;
-
-	bts rbox mgw_msc [label="Channel Request from Handover Decision"];
-	bsc note bsc [label="target lchan typically already chosen by Handover Decision"];
-	bsc -> bsc_gscon [label="GSCON_EV_HO_START (intra-BSC)"];
-	bsc_lchan <- bsc_gscon [label="lchan_activate(lchan, FOR_HANDOVER)"];
-	bsc_lchan rbox bsc_lchan [label="Continue at\nlchan_activate()\n"];
-	|||;
-	|||;
-
-	bts rbox mgw_msc [label="Channel Request from intra-BSC-MT-Handover"];
-	bsc_gscon <- mgw_msc [label="BSSMAP Handover Request"];
-	bsc_gscon box bsc_gscon [label="lchan_select_by_chan_mode(chan_mode)"];
-	bsc box bsc [label="lchan_activate(lchan, FOR_HANDOVER)"];
-	bsc_lchan rbox bsc_lchan [label="Continue at\nlchan_activate()\n"];
-	|||;
-	|||;
-	bts rbox mgw_msc [label="lchan_activate()"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_\nWAIT_TS_READY\n(timeout: ? s, Tnnnn)"];
-	|||;
-	|||;
-	--- [label="TCH?"];
-	bsc_lchan note bsc_gscon [label="This is skipped when FOR_MS_CHANNEL_REQUEST. If the MS requests
-		a TCH lchan, and we end up actually giving it a TCH because no SDCCH are available, we
-		can not set up an RTP stream because there is not even an L3 conn yet."];
-	bsc_lchan note bsc_gscon [label="The lchan FSM asks the conn FSM to have an MGW endpoint ready as
-		early as possible. Either the conn already has such MGW endpoint from a previous lchan,
-		in which case it immediately replies, or it requests one from the MGW, in which case we
-		wait for a response in 'TCH? (2)' below."];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_ENSURE_MGW_ENDPOINT"];
-	--- [label="IF conn has user_plane.fi_bts in state ST_READY"];
-	bsc_lchan <- bsc_gscon [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
-	bsc_lchan box bsc_lchan [label="mgw_endpoint_available = true"];
-	bsc_lchan note bsc_lchan [label="lchan_activate() continues"];
-	--- [label="ELSE (no MGW endpoint available yet)"];
-	bsc_gscon => mgw_msc [label="CRCX (for BTS) via mgcp_conn_create()"];
-	bsc_gscon abox bsc_gscon [label="ST_WAIT_CRCX_BTS\n(timeout: ? s, Tnnnn)"];
-	bsc_lchan <- bsc_gscon [label="(event dispatch returns)"];
-	bsc_lchan note bsc_lchan [label="lchan_activate() continues"];
 	...;
-	bsc_gscon note bsc_gscon [label="async:"];
-	bsc_gscon <= mgw_msc [label="CRCX OK (for BTS)"];
-	bsc_lchan <- bsc_gscon [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
-	bsc_lchan box bsc_lchan [label="mgw_endpoint_available = true"];
-	bsc_lchan note bsc_lchan [label="As soon as we reach LCHAN_ST_WAIT_MGW_ENDPOINT_AVAILABLE, this triggers
-		immedate action (s.b.), but until then, only the flag gets set to true."];
+	ms => lchan [label="RLL Establish Ind"];
+	lchan abox lchan [label="LCHAN_ST_\nESTABLISHED"];
+	lchan box lchan [label="lchan_on_fully_established()"];
+	--- [label="IF FOR_MS_CHANNEL_REQUEST"];
+	ms note lchan [label="No action required. The MS will have sent an L3 message in the RLL
+		Establish Ind and is then free to dispatch DTAP."];
+	--- [label="ELSE: FOR_ASSIGNMENT"];
+	lchan rbox lchan [label="dispatch\nASSIGNMENT_EV_\nLCHAN_ESTABLISHED\n(see Assignment FSM diagrams)"];
+	--- [label="ELSE: FOR_HANDOVER"];
+	lchan rbox lchan [label="dispatch\nHO_EV_LCHAN_ESTABLISHED\n(see Handover FSM diagrams)"];
+	--- [label="END"];
 	...;
-	--- [label="CRCX timeout"];
-	bsc_gscon note bsc_gscon [label="conn FSM should fire on CRCX timeout"];
-	bsc_lchan <- bsc_gscon [label="LCHAN_EV_MGW_ENDPOINT_ERROR"];
-	bsc_gscon note bsc_gscon [label="conn FSM should not assume anything and wait for
-		GSCON_EV_LCHAN_ALLOC_ERROR"];
-	bsc_lchan rbox bsc_lchan [label="Do 'On any error'"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
-	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
-	--- [label="END: 'TCH?'"];
-	|||;
-	|||;
-
-	bsc_lchan box bsc_lchan [label="lchan_activate() exits"];
-	bsc_lchan note bsc_lchan [label="still in\nlchan_request()\nLCHAN_ST_WAIT_\nTS_READY"];
-	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED"];
+	--- [label="IF requires_voice_stream"];
+	lchan rbox lchan [label="Assignment or Handover FSM:"];
+	lchan -> mgwep [label="CRCX/MDCX to-MSC"];
 	...;
-	--- [label="on error from TS or timeout:"];
-	bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_ERROR"];
-	bsc_lchan rbox bsc_lchan [label="Do 'On any error'"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
-	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
-	---;
-	...;
-	bsc_ts abox bsc_ts [label="TS_ST_IN_USE"];
-	bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_READY"];
-	bsc_lchan box bsc_lchan [label="lchan_fsm_\npre_lchan_activ()"];
-
-	|||;
-	|||;
-	bts rbox mgw_msc [label="mode FOR_MS_CHANNEL_REQUEST"];
-	bts note bsc_lchan [label="This is the simple case where the MS requested a channel, and there is no
-		L3 conn to the MSC; no matter if this is SDDCH or a TCH channel type, we will not prepare
-		an RTP stream."];
-
-	bsc_lchan note bsc_lchan [label="still in lchan_fsm_\npre_lchan_activ()"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nACTIV_ACK\n(timeout: ? s, Tnnnn)"];
-	bts <= bsc_lchan [label="RSL Chan Activ (RSL_ACT_INTRA_IMM_ASS)"];
-	bts note bsc_lchan [label="If any errors occur from now on, we don't want to send an RR Immediate
-		Assignment Reject anymore."];
-	bsc_lchan box bsc_lchan [label="sent_chan_activ = true"];
-	...;
-	--- [label="on timeout"];
-	bsc_lchan rbox bsc_lchan [label="Continue at: 'On any error', 'unrecoverable'"];
-	---;
-	...;
-	bts => bsc_lchan [label="RSL Chan Activ ACK"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRLL_ESTABLISH\nT3101"];
-	bsc_lchan note bsc_lchan [label="Now the lchan is assigned, but has no L3 conn yet. On errors,
-		this will either go into graceful release or into broken state, but will not trigger any
-		events to a (non-existing) conn."];
-	...;
-	--- [label="on timeout"];
-	bts <= bsc_lchan [label="RSL RF Channel Release"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_RF_RELEASE_ACK\n(T?, 4s)"];
-	---;
-	...;
-	bts => bsc_lchan [label="RLL Establish Ind"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
-	|||;
-	|||;
-	bts rbox mgw_msc [label="modes FOR_ASSIGNMENT and FOR_HANDOVER"];
-
-	bsc_lchan note bsc_lchan [label="still in lchan_fsm_\npre_lchan_activ()"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nACTIV_ACK\n(timeout: ? s, Tnnnn)"];
-	bts <= bsc_lchan [label="RSL Chan Activ (RSL_ACT_INTRA_NORM_ASS)",ID=FOR_ASSIGNMENT];
-	bts <= bsc_lchan [label="RSL Chan Activ (RSL_ACT_INTER_ASYNC)",ID=FOR_HANDOVER];
-	...;
-	--- [label="on timeout"];
-	bsc_lchan rbox bsc_lchan [label="Continue at: 'On any error', 'unrecoverable'"];
-	---;
-	bts => bsc_lchan [label="RSL Chan Activ ACK"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRLL_ESTABLISH\nT3101"];
-	...;
-	--- [label="on timeout"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
-	bsc_lchan -> bsc_lchan [label="lchan_fsm_pre_rf_release()"];
-	---;
-	...;
-	bts => bsc_lchan [label="RLL Establish Indication"];
-	|||;
-
-	--- [label="TCH? (2)"];
-	--- [label="mgw_endpoint_available == false?"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nMGW_ENDPOINT_\nAVAILABLE"];
-	bsc_lchan note bsc_lchan [label="rely on conn FSM timeout; apply only a long sanity timeout."];
-	...;
-	bsc_gscon <= mgw_msc [label="CRCX OK (for BTS)"];
-	bsc_lchan <- bsc_gscon [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
-	bsc_lchan box bsc_lchan [label="mgw_endpoint_available = true"];
-	bsc_lchan <- bsc_lchan [label="re-invoke lchan_fsm_pre_lchan_activ()"];
-	--- [label="END: 'TCH? (2)'"];
-	|||;
-
-	--- [label="is BTS using IPA Abis? (osmo-bts, ip.access)"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nIPACC_CRCX_ACK\n(timeout: ? s, Tnnnn)"];
-	bts <= bsc_lchan [label="IPACC CRCX"];
-	...;
-	--- [label="on timeout"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
-	bsc_lchan -> bsc_lchan [label="lchan_graceful_release()"];
-	---;
-	...;
-	bts => bsc_lchan [label="IPACC CRCX ACK"];
-	bts note bsc_lchan [label="The IPACC CRCX ACK tells us what port the IPA Abis based BTS has
-		assigned to this lchan. AoIP: we need to forward this to the MGW (BTS side) with an MDCX;
-		SCCPlite: we forward this to the MSC during BSSMAP Assignment Complete (TODO: is this
-		correct??)"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nIPACC_MDCX_ACK\n(timeout: ? s, Tnnnn)"];
-	bts <= bsc_lchan [label="IPACC MDCX"];
-	bts note bsc_lchan [label="The IPACC MDCX tells IPA Abis based BTSes the IP address and RTP port
-		assigned by the BTS side of the MGW. AoIP: the MGW CRCX (BTS) must thus happen before
-		this; SCCPlite: the RTP port is already known from the timeslot+multiplex information."];
-	...;
-	--- [label="on timeout"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
-	bsc_lchan -> bsc_lchan [label="lchan_graceful_release()"];
-	---;
-	...;
-	bts => bsc_lchan [label="IPACC MDCX ACK"];
-	--- [label="END: is BTS using IPA Abis? (osmo-bts, ip.access)"];
-	|||;
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
-	bsc_lchan box bsc_lchan [label="lchan_fsm_post_lchan_activ()"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ACTIVE"];
-	bts <= bsc_gscon [label="RR Assignment",ID="BSSMAP Assignment Request"];
-	bts <= bsc_gscon [label="RR Handover Command",ID="intra-BSC HO"];
-	bsc_gscon => mgw_msc [label="BSSMAP Handover\nRequest Acknowledge",ID="inter-BSC-MT HO"];
-	...;
-	---[label="On error"];
-	bsc_lchan rbox bsc_lchan [label="Continue at 'When the lchan is no longer used'"];
-	---;
-	...;
-
-	bts => bsc_gscon [label="RR Assignment Complete",ID="BSSMAP Assignment Request"];
-	bts => bsc_gscon [label="RR Handover Detect",ID="intra-BSC HO"];
-	bts => bsc_gscon [label="RR Handover Accept",ID="inter-BSC-MT HO"];
-	bsc_gscon note bsc_gscon [label="conn FSM takes care of MGW endpoints for BTS side (possibly
-		redirect) and MSC side (possibly create). More information in e.g. assignment.msc and
-		handover.msc"];
+	lchan <- mgwep [label="OK"];
+	lchan box lchan [label="gscon_change_primary_lchan()"];
+	lchan -> rtp [label="LCHAN_RTP_EV_ESTABLISHED"];
+	rtp abox rtp [label="LCHAN_RTP_ST_\nESTABLISHED"];
+	rtp box rtp [label="Forget any Rollback info"];
+	--- [label="END: requires_voice_stream"];
 
 	...;
 	...;
 	...;
 
-	bts rbox mgw_msc [label="When the lchan is no longer used"];
-	--- [label="IF the MS or BTS release the lchan"];
-	bts -> bsc_lchan [label="RLL Release Ind for SAPI=0"];
-	--- [label="IF the BSC other than the conn FSM decides to release"];
-	bsc -> bsc_lchan [label="LCHAN_EV_RELEASE"];
-	--- [label="IF the MSC or conn FSM release the lchan"];
-	bsc_lchan <- bsc_gscon [label="LCHAN_EV_RELEASE"];
-	---;
-	bsc note bsc_gscon [label="The LCHAN_EV_RELEASE's data pointer possibly indicates an error
-		cause"];
-	bsc_lchan note bsc_gscon [label="If the conn FSM requested a release, it probably has already
-	forgotten about this lchan. However, if the MS/BTS initiated the release, make sure the conn FSM
-	is informed:"];
-	bsc_lchan box bsc_lchan [label="lchan_graceful_release()"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nSAPIS_RELEASED\nT3109"];
-	--- [label="TCH and got as far as Chan Activ Ack?"];
-	bts <= bsc_lchan [label="RSL Deactivate SACCH"];
-	---;
-	bts <= bsc_lchan [label="RLL Release Request (Local End)..."];
-	bts <= bsc_lchan [label="...for all SAPIs except [0]"];
-	|||;
-	--- [label="SAPI[0] in use?"];
-	bsc_lchan note bsc_lchan [label="for bts->nokia.no_loc_rel_cnf we do not expect Release Confirm
-		messages and this state immediately advances to lchan_fsm_pre_rf_release()"];
+	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"];
+	lchan abox lchan [label="LCHAN_ST_WAIT_RLL_RTP_RELEASED"];
+	lchan rbox lchan [label="Continue at 'common release' below"];
 	...;
-	--- [label="on timeout"];
-	bsc_lchan box bsc_lchan [label="Anyway try RF Channel Release, continue
-		with lchan_fsm_wait_before_rf_release()"];
-	---;
 	...;
-	bts => bsc_lchan [label="RLL Release Confirm..."];
-	bts => bsc_lchan [label="...for each SAPI except [0]"];
-	bsc_lchan box bsc_lchan [label="Stay in\nLCHAN_ST_WAIT_\nSAPIS_RELEASED\nuntil only SAPI[0] remains active"];
-	--- [label="END: 'SAPI[0] in use?'"];
-	|||;
+	ms rbox mgwep [label="When the BSC decides to release the lchan"];
+	lchan box lchan [label="lchan_release()"];
+	lchan abox lchan [label="LCHAN_ST_WAIT_RLL_RTP_RELEASED"];
+	ms <= lchan [label="RR Release"];
+	lchan rbox lchan [label="common release"];
+	--- [label="IF RTP FSM present"];
+	lchan -> rtp [label="LCHAN_RTP_EV_RELEASE"];
+	--- [label="END: RTP FSM present"];
+	ms <= lchan [label="RSL Deactivate SACCH"];
+	ms <= lchan [label="RSL Release Request (Local End)",ID="for each SAPI except [0]"];
+	lchan note lchan [label="for ms->nokia.no_loc_rel_cnf we do not expect Release Confirm
+		messages and immediately mark all SAPIs as released"];
 
-	bsc_lchan box bsc_lchan [label="lchan_fsm_wait_before_rf_release()"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_FORGET_LCHAN (data=lchan)"];
-	bsc_gscon note bsc_gscon [label="conn FSM immediately forgets about the lchan"];
-	bsc_gscon => mgw_msc [label="BSSMAP Clear Request?"];
 	...;
-	bsc_lchan box bsc_lchan [label="T3111 expires"];
-	bsc_lchan box bsc_lchan [label="lchan_fsm_pre_rf_release()"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\nT3111"];
-	bsc_lchan box bsc_lchan [label="for each bsc_rll_req matching this lchan: disable timer, call
-		cb(BSC_RLLR_IND_REL_IND)"];
-	bts <= bsc_lchan [label="RSL RF Channel Release"];
+	lchan <- rtp [label="LCHAN_EV_RTP_RELEASED"];
 	...;
-	--- [label="on timeout"];
-	bsc_lchan rbox bsc_lchan [label="Continue at: 'On any error', 'unrecoverable'"];
-	---;
+	ms => lchan [label="RLL Release Confirm",ID="for each SAPI except [0]"];
 	...;
-	bts => bsc_lchan [label="RSL RF Channel Release Ack"];
-
-	bsc_lchan box bsc_lchan [label="lchan_fsm_post_rf_release()"];
+	lchan box lchan [label="Stay in\nLCHAN_ST_WAIT_\nRLL_RTP_RELEASED\nuntil only SAPI[0] remains active"];
+	lchan abox lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
+	...;
+	lchan box lchan [label="T3111 expires"];
+	lchan box lchan [label="lchan_fsm_pre_rf_release()"];
+	lchan abox lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\nT3111"];
+	ms <= lchan [label="RSL RF Channel Release"];
+	...;
+	lchan rbox lchan [label="On timeout, continue at: 'On any error', 'unrecoverable'"];
+	...;
+	ms => lchan [label="RSL RF Channel Release Ack"];
 	|||;
-	--- [label="IF an error cause was indicated on LCHAN_EV_RELEASE"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nAFTER_ERROR\n(timeout: T3111+2 s, T?)"];
+	--- [label="IF release_in_error"];
+	lchan abox lchan [label="LCHAN_ST_WAIT_\nAFTER_ERROR\n(timeout: T3111+2 s, T993111)"];
 	...;
-	bsc_lchan box bsc_lchan [label="timer expires"];
-	--- [label="END: 'an error cause was indicated on LCHAN_EV_RELEASE'"];
+	lchan box lchan [label="timer expires"];
+	--- [label="END: release_in_error"];
 	|||;
-	bsc_lchan box bsc_lchan [label="lchan_fsm_release_complete()"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
-	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
-	bsc_ts abox bsc_ts [label="TS_ST_UNUSED"];
+	lchan abox lchan [label="LCHAN_ST_UNUSED"];
+	ts <- lchan [label="TS_EV_LCHAN_UNUSED"];
+	|||;
 	|||;
 	|||;
 
-	bts rbox mgw_msc [label="On any error"];
+	ms rbox mgwep [label="On any error"];
 	|||;
-	--- [label="IF FOR_MS_CHANNEL_REQUEST && !sent_chan_activ"];
-	bts <= bsc_lchan [label="RR Immediate Assign Reject"];
+	--- [label="IF FOR_MS_CHANNEL_REQUEST"];
+	ms <= lchan [label="RR Immediate Assign Reject"];
+	--- [label="ELSE: FOR_ASSIGNMENT"];
+	lchan rbox lchan [label="dispatch\nASSIGNMENT_EV_\nLCHAN_ERROR\n(see Assignment FSM diagrams)"];
+	--- [label="ELSE: FOR_HANDOVER"];
+	lchan rbox lchan [label="dispatch\nHO_EV_LCHAN_ERROR\n(see Handover FSM diagrams)"];
+	--- [label="END"];
 	|||;
-	--- [label="IF FOR_ASSIGNMENT or FOR_HANDOVER"];
-	bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
-	bsc_gscon note bsc_gscon [label="conn FSM shall immediately 'forget' the lchan"];
-	bsc_gscon => mgw_msc [label="BSSMAP\nAssignment Failure",ID=FOR_ASSIGNMENT];
-	bsc_gscon => mgw_msc [label="BSSMAP\nHandover Failure",ID="inter-BSC-MT HO"];
-	---;
+	--- [label="IF fi_rtp present"];
+	lchan -> rtp [label="LCHAN_RTP_EV_ROLLBACK"];
+	rtp rbox rtp [label="If to-BTS is not established yet, ROLLBACK is synonymous to LCHAN_RTP_EV_RELEASE"];
+	rtp rbox rtp [label="If there is no old_lchan, just DLCX instead"];
+	rtp abox rtp [label="LCHAN_RTP_ST_ROLLBACK"];
+	rtp box rtp [label="connect_mgw_endpoint_to_lchan()\nusing old_lchan"];
+	rtp -> mgwep [label="MDCX to-BTS"];
+	mgwep rbox mgwep [label="MGCP: MDCX"];
+	...;
+	mgwep rbox mgwep [label="MGCP: MDCX OK"];
+	rtp <- mgwep [label="LCHAN_RTP_EV_MGW_ENDPOINT_CONFIGURED"];
+	rtp abox rtp [label="terminate"];
+	lchan <- rtp [label="LCHAN_EV_RTP_RELEASED"];
+	--- [label="END: fi_rtp present"];
+	|||;
 	|||;
 	--- [label="IF unrecoverable error"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_BORKEN"];
-	bsc_lchan note bsc_lchan [label="The broken state usually stays around
+	lchan abox lchan [label="LCHAN_ST_BORKEN"];
+	ms note lchan [label="The broken state usually stays around
 		until the BTS disconnects."];
 	...;
-	bts note bsc_lchan [label="If an ACK comes in late, for specific BTS models, we may choose to
+	ms note lchan [label="If an ACK comes in late, for specific BTS models, we may choose to
 		'repair' the lchan so that it is usable again."];
-	bts -> bsc_lchan [label="Chan Release ACK"];
-	bsc_lchan -> bsc_lchan [label="lchan_fsm_post_rf_release()"];
+	ms -> lchan [label="RF Chan Release ACK"];
+	lchan rbox lchan [label="continue above at\nLCHAN_ST_WAIT_\nAFTER_ERROR"];
 }
diff --git a/doc/legend_for_fsm_diagrams.dot b/doc/legend_for_fsm_diagrams.dot
new file mode 100644
index 0000000..732a894
--- /dev/null
+++ b/doc/legend_for_fsm_diagrams.dot
@@ -0,0 +1,24 @@
+digraph G {
+rankdir=TB
+labelloc=t; label="LEGEND FOR FSM GRAPHS"
+
+	box [label="function_call()\nputs FSM into state",shape="box"]
+	STATE [label="FSM_STATE"]
+	STATE2 [label="FSM_STATE"]
+	STATE3 [label="FSM_STATE"]
+	box -> STATE
+	STATE -> STATE2 [label="state transition"]
+	STATE2 -> STATE3
+
+	STATE -> STATE3 [label="transition\non error",style=dashed]
+
+	other [label="other FSM\ninstance\nor remote program",shape=box3d]
+	STATE2 -> other [label="event",style=dotted]
+	other -> STATE2 [label="event",style=dotted]
+
+	terminate [shape=octagon]
+	STATE3 -> terminate
+
+	err [label="common error\ntransition",shape=box,style=dashed]
+	err -> STATE3 [style=dashed]
+}
diff --git a/doc/legend_for_ladder_diagrams.msc b/doc/legend_for_ladder_diagrams.msc
new file mode 100644
index 0000000..a581fe4
--- /dev/null
+++ b/doc/legend_for_ladder_diagrams.msc
@@ -0,0 +1,29 @@
+msc {
+	A [label="FSM instance"],B [label="FSM instance"], C [label="remote program"];
+	|||;
+	||| [label="LADDER DIAGRAM LEGEND"];
+	|||;
+
+	A rbox C [label="Group Heading"];
+
+	A box A [label="function call or action"];
+	A -> B [label="event within program"];
+	B abox B [label="enter FSM state"];
+	B => C [label="network protocol message"];
+	...;
+	... [label="asynchronous wait time"];
+	...;
+	B <= C [label="network protocol message"];
+	|||;
+	||| [label="continue synchronously"];
+	|||;
+	A <- B [label="event within program"];
+	A rbox A [label="flow detail: 'continue at...'"];
+	...;
+	...;
+	--- [label="IF conditional"];
+	||| [label="..."];
+	--- [label="END: conditional"];
+	...;
+	B note B [label="arbitrary prose"];
+}
diff --git a/doc/mgw-endpoint-fsm.dot b/doc/mgw-endpoint-fsm.dot
new file mode 100644
index 0000000..ac7c2bf
--- /dev/null
+++ b/doc/mgw-endpoint-fsm.dot
@@ -0,0 +1,24 @@
+digraph G {
+rankdir=TB
+labelloc=t; label="MGW Endpoint FSM"
+
+	gscon_ensure_mgw_endpoint [label="gscon_ensure_mgw_endpoint()",shape="box"]
+	UNUSED
+	WAIT_MGW_RESPONSE
+	IN_USE
+	terminate [shape=octagon]
+	mgcp [label="mgcp client FSM\n(libosmo-mgcp-client)",shape=box3d]
+	notify [label="notify target FI",shape=box3d]
+	gscon [label="parent FI\n(gscon)",shape=box3d]
+
+	gscon_ensure_mgw_endpoint -> UNUSED
+	UNUSED -> WAIT_MGW_RESPONSE [label="first\nmgw_endpoint_ci_request(CRCX)"]
+	WAIT_MGW_RESPONSE -> mgcp [label="mgcp_conn_create()\nmgcp_conn_modify()\nmgcp_conn_delete()",style=dotted]
+	mgcp -> WAIT_MGW_RESPONSE [label="CI[i] event",style=dotted]
+	WAIT_MGW_RESPONSE -> IN_USE
+	IN_USE -> notify [label="notify event for\nindividual CI request",style=dotted]
+	IN_USE -> WAIT_MGW_RESPONSE [label="additional\nmgw_endpoint_ci_request()\nCRCX,MDCX,DLCX"]
+
+	WAIT_MGW_RESPONSE -> terminate [label="all CI DLCX'd"]
+	terminate -> gscon [label="GSCON_EV_FORGET_MGW_ENDPOINT",style=dotted]
+}
diff --git a/doc/mgw-endpoint.msc b/doc/mgw-endpoint.msc
new file mode 100644
index 0000000..7084d1d
--- /dev/null
+++ b/doc/mgw-endpoint.msc
@@ -0,0 +1,105 @@
+msc {
+	hscale=2;
+	notify [label="calling FSM"], mgwep[label="MGW endpoint FSM"], mgcp[label="mgcp client FSM"],
+	mgw[label="MGW"];
+
+	notify note mgw [label="MGW endpoint FSM\nmanages multiple CI for one endpoint"];
+
+	|||;
+
+	notify rbox notify [label="conn FSM"];
+	notify box notify [label="gscon_ensure_mgw_endpoint()"];
+	notify -> mgwep [label="mgw_endpoint_alloc()"];
+	mgwep abox mgwep [label="MGWEP_ST_UNUSED"];
+
+	...;
+	...;
+	...;
+	notify rbox mgw [label="CRCX"];
+
+	notify rbox notify [label="lchan RTP FSM"];
+	notify -> mgwep [label="mgw_endpoint_ci_add()"];
+	mgwep note mgwep [label="Return an unassigned endpoint CI slot in the local array"];
+	...;
+	mgwep note mgwep [label="First request on a CI must be a CRCX"];
+	notify -> mgwep [label="mgw_endpoint_ci_request(CRCX)"];
+	notify note mgwep [label="verb=CRCX\nverb_info='rtpbridge/*@mgw'\nnotify_event"];
+	mgwep box mgwep [label="CI[x].pending=true"];
+	mgwep abox mgwep [label="MGWEP_ST_WAIT_MGW_RESPONSE"];
+	|||;
+	notify note mgwep [label="If more mgw_endpoint_ci_request() are triggered, they will be set to
+		'pending' and wait until all ongoing requests are through and MGWEP_ST_IN_USE is
+		reached."];
+	|||;
+	mgwep box mgwep [label="for each pending CI:\nsend_verb()"];
+	mgwep -> mgcp [label="CI[x]: mgcp_conn_create()"];
+	mgwep note mgcp [label="Each CI[i] has two events from the FSM instance event range assigned, one
+		for success, one for failure. These are passed to the mgcp client FSM."];
+	mgcp => mgw [label="CRCX"];
+	...;
+	mgcp <= mgw [label="CRCX OK"];
+	mgcp note mgw [label="MGW returns:\n'rtpbridge/123 at mgw',\nnew CI identifier '123abc',\n
+		MGW side RTP IP:port"];
+	mgwep <- mgcp [label="CI[x] success event"];
+	mgwep box mgwep [label="on_success(CI[x])"];
+	mgwep note mgwep [label="CI[x].rtp_info = IP:port\nmgcp_ci_str = '123abc'\n
+		endpoint name = 'rtpbridge/123 at mgw'"];
+	notify <- mgwep [label="notify_event from mgw_endpoint_ci_request()"];
+	notify note mgwep [label="notify_event will be one of:\n
+		LCHAN_RTP_EV_MGW_ENDPOINT_AVAILABLE (towards BTS)\n
+		ASSIGNMENT_EV_MSC_MGW_OK (towards MSC)\n
+		HO_EV_MSC_MGW_OK (towards MSC)"];
+	mgwep abox mgwep [label="MGWEP_ST_IN_USE"];
+
+	...;
+	...;
+	...;
+	notify rbox mgw [label="MDCX"];
+
+	mgwep note mgwep [label="Second or later request on a CI must be MDCX or DLCX"];
+	notify -> mgwep [label="mgw_endpoint_ci_request(MDCX)"];
+	notify note mgwep [label="verb=MDCX\nverb_info=BTS RTP IP:port\n
+		automatic: full endpoint name as from CRCX OK\n
+		notify_event\n"];
+	mgwep box mgwep [label="CI[x].pending=true"];
+	mgwep abox mgwep [label="MGWEP_ST_WAIT_MGW_RESPONSE"];
+	mgwep box mgwep [label="for each pending CI:\nsend_verb()"];
+	mgwep -> mgcp [label="CI[x]: mgcp_conn_modify()"];
+	mgcp => mgw [label="MDCX"];
+	...;
+	mgcp <= mgw [label="MDCX OK"];
+	mgwep <- mgcp [label="CI[x] success event"];
+	mgwep box mgwep [label="on_success(CI[x])"];
+	notify <- mgwep [label="notify_event from mgw_endpoint_ci_request()"];
+	notify note mgwep [label="notify_event will be one of:\n
+		LCHAN_RTP_EV_MGW_ENDPOINT_CONFIGURED (towards BTS)\n
+		ASSIGNMENT_EV_MSC_MGW_OK (towards MSC)\n
+		HO_EV_MSC_MGW_OK (towards MSC)"];
+	mgwep abox mgwep [label="MGWEP_ST_IN_USE"];
+
+	...;
+	...;
+	...;
+	notify rbox mgw [label="DLCX"];
+
+	notify -> mgwep [label="mgw_endpoint_ci_dlcx()"];
+	mgwep box mgwep [label="mgw_endpoint_ci_request(DLCX)"];
+	mgwep box mgwep [label="CI[x].pending=true"];
+	mgwep abox mgwep [label="MGWEP_ST_WAIT_MGW_RESPONSE"];
+	mgwep box mgwep [label="for each pending CI:\nsend_verb()"];
+	mgwep -> mgcp [label="CI[x]: mgcp_conn_delete()"];
+	mgcp => mgw [label="DLCX"];
+	mgcp box mgcp [label="detach from parent fi"];
+	mgwep box mgwep [label="forget and clear CI[x]"];
+	--- [label="IF other CI remain valid"];
+	mgwep abox mgwep [label="MGWEP_ST_IN_USE"];
+	--- [label="IF no CI remain on endpoint"];
+	mgwep abox mgwep [label="terminate"];
+	notify rbox notify [label="conn FSM"];
+	notify <- mgwep [label="GSCON_EV_FORGET_MGW_ENDPOINT"];
+	---;
+	...;
+	mgcp <= mgw [label="DLCX OK"];
+	mgcp abox mgcp [label="terminate"];
+
+}
diff --git a/doc/ms-channel-request.msc b/doc/ms-channel-request.msc
deleted file mode 100644
index 1c5b4bf..0000000
--- a/doc/ms-channel-request.msc
+++ /dev/null
@@ -1,59 +0,0 @@
-msc {
-	hscale=2;
-	ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_lchan[label="BSC lchan FSM"];
-
-	ms note bsc_lchan [label="lchan allocation sequence for RSL Channel Request"];
-
-	ms => bts [label="RR Channel Request"];
-	bts => bsc [label="RSL Channel Request"];
-	bsc box bsc [label="rsl_rx_chan_rqd()"];
-	bsc note bsc [label="Obtain RACH data from Request: - Reference - Access Delay (TA)
-		- Request Reason - Channel Type"];
-	bsc note bsc [label="If the reason is PDCH, the RACH Request is forwarded to PCU and BSC is no
-		longer concerned (rsl_rx_pchan_rqd())."];
-	bsc note bsc [label="Always try to allocate an SDCCH regardless of the requested type, only if no
-		SDCCH is available, look for the actually requested channel type."];
-	bsc box bsc [label="lchan_select_by_type(SDCCH)"];
-
-	--- [label="IF no lchan is available (neither SDCCH nor requested type)"];
-	bsc note bsc [label="Figure out T3122 value from bts->T3122, network->T3122 or
-		GSM_T3122_DEFAULT"];
-	bsc box bsc [label="rsl_send_imm_ass_rej(wait_ind=T3122)"];
-	bsc note bsc [label="..."];
-	bts <= bsc [label="RR Immediate Assign Reject"];
-	ms <= bts [label="RR Immediate Assign Reject (possibly grouped with up to 4 others)"];
-	bsc note bsc [label="rsl_rx_pchan_rqd() exits, no channel is allocated."];
-	--- [label="END: no lchan is available"];
-
-	bsc box bsc [label="Store RACH data in lchan->rqd_ref, rqd_ta"];
-	bsc -> bsc_lchan [label="lchan_allocate(FOR_MS_CHANNEL_REQUEST)"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_ACTIV_ACK\nT3103"];
-	bsc_lchan note bsc_lchan [label="The lchan FSM knows that FOR_MS_CHANNEL_REQUEST is about
-		Immediate Assignment."];
-	bts <= bsc_lchan [label="RSL Chan Activ (Immediate Assignment)"];
-	...;
-	--- [label="on any error"];
-	bts <= bsc_lchan [label="RR Immediate Assign Reject"];
-	ms <= bts [label="RR Immediate Assign Reject (possibly grouped with up to 4 others)"];
-	---;
-	...;
-	bts => bsc_lchan [label="RSL Chan Activ ACK"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRLL_ESTABLISH\ncontinue T3103"];
-	...;
-	--- [label="on timeout"];
-	bsc_lchan box bsc_lchan [label="lchan_error_release(deact_sacch=true)"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_RF_RELEASE_ACK"];
-	bts <= bsc_lchan [label="RLL Release Request (Local End)..."];
-	bts <= bsc_lchan [label="...for all SAPIs including [0]"];
-	bts <= bsc_lchan [label="RSL Deactivate SACCH"];
-	bts <= bsc_lchan [label="RSL RF Channel Release"];
-	...;
-	bts => bsc_lchan [label="RSL RF Channel Release ACK"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_AFTER_ERROR"];
-	...;
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
-	---;
-	ms => bsc_lchan [label="RLL Establish Ind"];
-	bsc_lchan box bsc_lchan [label="associate lchan FSM with new conn FSM"];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
-}
diff --git a/doc/timeslot-fsm.dot b/doc/timeslot-fsm.dot
index 79e56c9..95a4e1f 100644
--- a/doc/timeslot-fsm.dot
+++ b/doc/timeslot-fsm.dot
@@ -1,10 +1,11 @@
 digraph G {
-rankdir=TB;
+rankdir=TB
+labelloc=t; label="Timeslot FSM"
 	
 	invisible [style="invisible"]
 	invisible2 [style="invisible"]
 	NOT_INITIALIZED
-	lchan [label="lchan FSM",shape=box3d];
+	lchan [label="lchan FSM",shape=box3d]
 	UNUSED
 	IN_USE
 	BORKEN
diff --git a/doc/timeslot.msc b/doc/timeslot.msc
index 9a8c360..02e7bb3 100644
--- a/doc/timeslot.msc
+++ b/doc/timeslot.msc
@@ -1,25 +1,24 @@
 msc {
-	hscale=2;
 	bts [label="MS/BTS"], bsc[label="BSC"], bsc_ts[label="BSC timeslot FSM"], bsc_lchan[label="BSC lchan FSM"];
 
-	bsc_ts abox bsc_ts [label="NOT_INITIALIZED (no timeout)"];
+	bsc_ts abox bsc_ts [label="NOT_INITIALIZED"];
 
 	...;
 	bsc note bsc_ts [label="OML and RSL may be established in any order"];
 	bts => bsc_ts [label="OML: Channel OPSTART ACK"];
 	bsc -> bsc_ts [label="RSL bootstrapped"];
-	bsc_ts abox bsc_ts [label="UNUSED (no timeout)"];
+	bsc_ts abox bsc_ts [label="UNUSED"];
 
 	|||;
 	bts rbox bsc_lchan [label="UNUSED, onenter"];
 	bsc_ts abox bsc_ts [label="UNUSED"];
 	--- [label="GPRS enabled?"];
 	--- [label="IF: dedicated PDCH?"];
-	bsc_ts abox bsc_ts [label="PDCH (no timeout)"];
+	bsc_ts abox bsc_ts [label="PDCH"];
 
 	|||;
 	--- [label="IF: dynamic timeslot"];
-	bsc_ts abox bsc_ts [label="WAIT_PDCH_ACT (?s, Tnnnn)"];
+	bsc_ts abox bsc_ts [label="WAIT_PDCH_ACT (4s, T23001)"];
 	bts <= bsc_ts [label="RSL Chan Activ of PDCH",ID="Osmocom style"];
 	bts <= bsc_ts [label="RSL PDCH Act",ID="ip.access style"];
 	...;
@@ -29,7 +28,7 @@
 	...;
 	bts => bsc_ts [label="RSL RF Chan Activ ACK",ID="Osmocom style"];
 	bts => bsc_ts [label="RSL PDCH Act ACK",ID="ip.access style"];
-	bsc_ts abox bsc_ts [label="PDCH (no timeout)"];
+	bsc_ts abox bsc_ts [label="PDCH"];
 
 	--- [label="END: GPRS enabled?"];
 	...;
@@ -43,12 +42,14 @@
 	bts <= bsc_lchan [label="RSL Chan Activ (and so on)"];
 	...;
 	bts rbox bsc_lchan [label="IN_USE, second lchan"];
+	bsc_ts abox bsc_ts [label="IN_USE"];
 	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED (data=lchan)"];
 	bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_READY"];
 	bts <= bsc_lchan [label="RSL Chan Activ (and so on)"];
 	...;
 	...;
 	bts rbox bsc_lchan [label="IN_USE, when lchan FSM releases (both regularly, or due to error)"];
+	bsc_ts abox bsc_ts [label="IN_USE"];
 	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED (data=lchan)"];
 	--- [label="IF all lchan->fi->state == LCHAN_ST_UNUSED"];
 	bsc_ts abox bsc_ts [label="UNUSED"];
@@ -57,13 +58,14 @@
 	...;
 
 
-	bts rbox bsc_lchan [label="PDCH on lchan request"];
+	bts rbox bsc_lchan [label="PDCH, on lchan request"];
 	bsc_ts note bsc_lchan [label="TS_EV_LCHAN_REQUESTED should only come in on
 		lchans where it makes sense, both from TS kind as well as not
 		conflicting with other users of the lchan."];
 
+	bsc_ts abox bsc_ts [label="PDCH"];
 	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED"];
-	bsc_ts abox bsc_ts [label="WAIT_PDCH_DEACT (?s, Tnnnn)"];
+	bsc_ts abox bsc_ts [label="WAIT_PDCH_DEACT (4s, T23001)"];
 	bts <= bsc_ts [label="RSL RF Chan Release of PDCH",ID="Osmocom style"];
 	bts <= bsc_ts [label="RSL PDCH Deact",ID="ip.access style"];
 	...;
diff --git a/doc/ts-and-lchan-fsm-lifecycle.msc b/doc/ts-and-lchan-fsm-lifecycle.msc
index 79d32c5..9275f1f 100644
--- a/doc/ts-and-lchan-fsm-lifecycle.msc
+++ b/doc/ts-and-lchan-fsm-lifecycle.msc
@@ -55,7 +55,7 @@
 	--- [label="dyn TS"];
 	bsc_ts box bsc_ts [label="onenter of TS_ST_UNUSED:"];
 	bsc_ts abox bsc_ts [label="TS_ST_WAIT_PDCH_ACT"];
-	...;
+	... [label="..."];
 	bsc_ts abox bsc_ts [label="PDCH"];
 	--- [label="END: dyn TS"];
 	--- [label="END: OML and RSL ready"];
@@ -65,13 +65,13 @@
 	bsc_lchan -> bsc_ts [label="TS_EV_LCHAN_REQUESTED"];
 	
 	--- [label="dyn TS"];
-	bsc_ts note bsc_ts [label="possibly switch from PDCH...\n(see timeslot FSM)"];
+	bsc_ts rbox bsc_ts [label="possibly switch from PDCH...\n(see timeslot FSM)"];
 	bsc_ts box bsc_ts [label="ts->pchan =\n requested GSM_PCHAN_XXX type"];
 	---;
 
 	bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_READY"];
 	bsc_lchan note bsc_lchan [label="RSL Chan Alloc and so fort..."];
-	bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
+	bsc_lchan abox bsc_lchan [label="LCHAN_ST_ESTABLISHED"];
 	...;
 	bsc -> bsc_lchan [label="LCHAN_EV_RELEASE"];
 	bsc_lchan note bsc_lchan [label="...RSL RF Chan Release..."];
@@ -79,7 +79,7 @@
 	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
 	bsc_ts abox bsc_ts [label="TS_ST_UNUSED"];
 	--- [label="dyn TS"];
-	bsc_ts note bsc_ts [label="possibly switch to PDCH"];
+	bsc_ts rbox bsc_ts [label="possibly switch to PDCH"];
 	---;
 	...;
 	...;
@@ -88,8 +88,8 @@
 	bsc -> bsc_ts [label="ts[*]:"];
 	bsc_ts abox bsc_ts [label="TS_ST_NOT_INITIALIZED"];
 	bsc_ts note bsc_lchan [label="If it's just the RSL being dropped, transition lchan FSMs to
-		LCHAN_ST_UNUSED, but keep them allocated. Unless OML is re-established, any vty pchan
-		modifications must not take effect."];
+		LCHAN_ST_UNUSED, but keep them allocated. Unless OML is re-established, any telnet
+		vty pchan modifications must not take effect."];
 	bsc_ts -> bsc_lchan [label="lchan[*]:"];
 	bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
 	bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED (ignored)"];

-- 
To view, visit https://gerrit.osmocom.org/9667
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I29e31b753e23a4207662e0e385a337e7df836f45
Gerrit-Change-Number: 9667
Gerrit-PatchSet: 15
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20180728/152e0f47/attachment.htm>


More information about the gerrit-log mailing list