aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/Makefile.am15
-rw-r--r--doc/assignment.msc248
-rw-r--r--doc/handover-inter-bsc-mo.msc37
-rw-r--r--doc/handover-inter-bsc-mt.msc154
-rw-r--r--doc/handover.msc241
-rw-r--r--doc/lchan-fsm.dot53
-rw-r--r--doc/lchan-release.msc190
-rw-r--r--doc/lchan.msc306
-rw-r--r--doc/ms-channel-request.msc68
-rw-r--r--doc/timeslot-fsm.dot36
-rw-r--r--doc/timeslot.msc98
-rw-r--r--doc/ts-and-lchan-fsm-lifecycle.msc116
12 files changed, 1097 insertions, 465 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 5fe5674a8..ca0470d01 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -7,11 +7,24 @@ msc: \
$(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 \
+ $(NULL)
+
+dot: \
+ $(builddir)/timeslot-fsm.png \
+ $(builddir)/lchan-fsm.png \
$(NULL)
$(builddir)/%.png: $(srcdir)/%.msc
mscgen -T png -o $@ $<
+$(builddir)/%.png: $(srcdir)/%.dot
+ dot -Tpng $< > $@
+
.PHONY: poll
poll:
- while true; do $(MAKE) msc; sleep 1; done
+ while true; do $(MAKE) msc dot; sleep 1; done
diff --git a/doc/assignment.msc b/doc/assignment.msc
index d470d014b..9f10ea1ba 100644
--- a/doc/assignment.msc
+++ b/doc/assignment.msc
@@ -1,190 +1,126 @@
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"], msc_[label="MSC"];
+ 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"];
- ms note msc_ [label="lchan allocation sequence for BSSMAP Assignment Request"];
+ ms note mgw_msc [label="lchan allocation sequence for BSSMAP Assignment Request"];
- bsc <= msc_ [label="BSSMAP Assignment Request"];
- bsc box bsc [label="bssmap_handle_assignm_req()"];
- bsc -> bsc_gscon [label="GSCON_EV_A_ASSIGNMENT_CMD"];
+ bsc_gscon <= mgw_msc [label="BSSMAP Assignment Request"];
+ bsc_gscon abox bsc_gscon [label="ST_ASSIGNMENT_\nWAIT_LCHAN"];
- --- [label="is the chan_mode a speech mode?"];
+ 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"];
+ ---;
+ |||;
+ bsc_gscon box bsc_gscon [label="store lchan pointer in conn->lchan_for_assignment"];
+ bsc_lchan <- bsc_gscon [label="lchan_activate(FOR_ASSIGNMENT)"];
+ ...;
+ |||;
+ --- [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"];
+ --- [label="END: 'on error'"];
+ ...;
+ ...;
- bsc_gscon abox bsc_gscon [label="ST_WAIT_CRCX_BTS (MGCP_MGW_TIMEOUT = 4s)"];
+ --- [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 => mgw [label="CRCX (for BTS)"];
- bsc_mgcp abox bsc_mgcp [label="ST_CRCX (MGCP_MGW_TIMEOUT = 4s)"];
- bsc_gscon note bsc_mgcp [label="two timeouts running in parallel"];
- bsc_gscon note bsc_mgcp [label="note: #define MGCP_MGW_TIMEOUT exists twice,
- once in libosmo-mgcp-client,
- once in bsc_subscr_conn_fsm.c"];
- bsc_mgcp -> bsc_gscon [label="mgcp_conn_create() exits"];
- bsc_gscon -> bsc [label="bssmap_handle_assignm_req() exits"];
+ 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"];
...;
--- [label="On Timeout"];
- bsc_gscon note bsc_gscon [label="The conn FSM likely timeouts first"];
- bsc_gscon => msc_ [label="BSSMAP Assignment Failure"];
- bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
- bsc_mgcp note bsc_mgcp [label="The MGCP FSM will timeout right after that, and terminate itself,
- emitting the parent_term event set upon mgcp_conn_create():"];
+ 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. There is code
- that would emit a BSSMAP Assignment Failure, but not in
- ST_ACTIVE"];
- --- [label="end: 'On Timeout'"];
+ 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'"];
...;
- bsc_mgcp <= mgw [label="CRCX OK (for BTS)"];
+ 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"];
- --- [label="end: 'is the chan_mode a speech mode?'"];
-
- bsc_gscon note bsc_gscon [label="for mode=sign, we're still handling GSCON_EV_A_ASSIGNMENT_CMD;
- for speech mode, we're handling GSCON_EV_MGW_CRCX_RESP_BTS"];
- bsc <- bsc_gscon [label="gsm0808_assign_req()"];
-
- 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="gsm0808_assign_req() returns early"];
- bsc_gscon abox bsc_gscon [label="ST_WAIT_ASS_COMPL (GSM0808_T10_VALUE=6s)"];
+ 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"];
...;
- 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!"];
...;
- 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"];
- bsc box bsc [label="lchan->state = LCHAN_S_ACT_REQ"];
- bts <= bsc [label="RSL Chan Activ"];
- --- [label="else (no dyn TS switchover)"];
-
- bsc box bsc [label="lchan->state = LCHAN_S_ACT_REQ"];
- bts <= bsc [label="RSL Chan Activ"];
- bsc -> bsc_gscon [label="gsm0808_assign_req() returns"];
- bsc_gscon abox bsc_gscon [label="ST_WAIT_ASS_COMPL (GSM0808_T10_VALUE=6s)"];
- ---;
+ 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 => msc_ [label="BSSMAP Assignment Failure"];
+ 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"];
- bsc_gscon note bsc_mgcp [linecolor="red",
- label="The mgcp FSM from CRCX above apparently lacks a cleanup action for this case.
- It should be cleaned up eventually when the conn is torn down, but we should
- release RTP endpoints as soon as possible."];
- --- [label="end: 'On Timeout'"];
- ...;
-
- 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="bsc_api.c handle_chan_ack()"];
- ms <= bsc [label="RR Assignment Command"];
-
- ...;
- ms note bsc_gscon [label="We rely on the overall conn FSM ST_WAIT_ASS_COMPL timeout."];
+ --- [label="END: 'On Timeout'"];
...;
-
- ms => bsc [label="RR Assignment Complete"];
- bsc box bsc [label="handle_ass_compl()"];
- --- [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->assign_fail()"];
- bsc -> bsc_gscon [label="GSCON_EV_RR_ASS_FAIL"];
- bsc note bsc_gscon [linecolor="orange",
- label="The name 'RR_ASS_FAIL' might suggest the event means an actual RR Assignment
- Failure message being received. Maybe this should be called GSCON_EV_ASSIGNMENT_ERROR."];
- ...;
- 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 => msc_ [label="BSSMAP Clear Request"];
- bsc note bsc_gscon [linecolor="red",
- label="Instead of sending an arbitrary message, the conn FSM should
- be explicitly instructed to clear the connection, to be able
- to notice if the MSC failed to respond to the Clear Request.
- Currently, this relies on the MSC responding with a Clear
- Command, hopefully, some time later."];
- --- [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"];
- --- [label="End: 'Release old lchan'"];
- bsc box bsc [label="still in handle_ass_compl()"];
- bsc note bsc [label="officially take over new lchan: conn->lchan = conn->secondary_lchan"];
- --- [label="is BTS using IPA Abis? (osmo-bts, ip.access)"];
- bts <= bsc [label="IPACC CRCX"];
- ---;
- bsc -> bsc [label="handle_ass_compl() calls bsc_api->assign_compl()"];
- --- [label="is BTS using IPA Abis? (osmo-bts, ip.access) && conn->user_plane.rtp_ip"];
- bsc box bsc [label="bsc_assign_compl()"];
- bsc note bsc [label="set ass_compl.valid = true,
- postponing GSCON_EV_RR_ASS_COMPL until after the
- IPACC MDCX ACK received in osmo_bsc_audio.c"];
- bsc box bsc [label="exit early: bsc_assign_compl()"];
- bsc box bsc [label="exit early: handle_ass_compl()"];
- bsc box bsc [label="osmo_bsc_audio.c"];
- bts => bsc [label="IPACC CRCX ACK"];
- bts <= bsc [label="IPACC MDCX"];
- bts => bsc [label="IPACC MDCX ACK"];
- bsc box bsc [label="handle_abisip_signal()"];
- bsc -> bsc_gscon [label="GSCON_EV_RR_ASS_COMPL"];
- --- [label="else"];
- bsc box bsc [label="bsc_assign_compl()"];
- bsc -> bsc_gscon [label="GSCON_EV_RR_ASS_COMPL"];
- --- ;
-
- --- [label="is chan_mode a speech mode?"];
+ 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 => mgw [label="MDCX (for BTS)"];
- bsc_mgcp <= mgw [label="MDCX OK"];
+ 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 [label="CRCX (for MSC)"];
- bsc_mgcp <= mgw [label="CRCX OK (for MSC)"];
+ 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 => msc_ [label="BSSMAP Assignment Complete"];
+ bsc_gscon => mgw_msc [label="BSSMAP Assignment Complete"];
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
}
diff --git a/doc/handover-inter-bsc-mo.msc b/doc/handover-inter-bsc-mo.msc
new file mode 100644
index 000000000..9aff7a728
--- /dev/null
+++ b/doc/handover-inter-bsc-mo.msc
@@ -0,0 +1,37 @@
+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
new file mode 100644
index 000000000..88a52daa7
--- /dev/null
+++ b/doc/handover-inter-bsc-mt.msc
@@ -0,0 +1,154 @@
+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.msc b/doc/handover.msc
index 8862dd97b..7529de602 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)"];
+ ...;
+ --- [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 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!"];
...;
- 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)"];
-
- ...;
- 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."];
+ ms note bsc_gscon [label="MS happily continues on the old lchan."];
+ bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
+ --- [label="END: 'On Timeout'"];
...;
- bts => bsc [label="IPACC MDCX ACK"];
- bts note bsc [label="IPACC MDCX ACK triggers no events or actions"];
- ---;
+ 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"];
...;
- 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."];
-
...;
- 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"];
+ 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"];
+
...;
--- [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"];
}
diff --git a/doc/lchan-fsm.dot b/doc/lchan-fsm.dot
new file mode 100644
index 000000000..dbb283cd1
--- /dev/null
+++ b/doc/lchan-fsm.dot
@@ -0,0 +1,53 @@
+digraph G {
+rankdir=TB;
+
+ 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
+
+ ts [label="timeslot FSM",shape=box3d];
+ gscon [label="conn FSM",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]
+
+ 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]
+
+ WAIT_BEFORE_RF_RELEASE -> WAIT_RF_RELEASE_ACK [label="T3111"]
+ WAIT_RF_RELEASE_ACK -> UNUSED
+ WAIT_RF_RELEASE_ACK -> WAIT_AFTER_ERROR [label="release was\ndue to error"]
+ WAIT_AFTER_ERROR -> UNUSED [label="T3111+2s"]
+
+ WAIT_TS_READY -> ts [label="TS_EV_\nLCHAN_\nREQUESTED",style=dotted,penwidth=3]
+ 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 -> 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]
+
+ 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]
+
+}
diff --git a/doc/lchan-release.msc b/doc/lchan-release.msc
index f75b559c1..017c9cf05 100644
--- a/doc/lchan-release.msc
+++ b/doc/lchan-release.msc
@@ -1,149 +1,83 @@
msc {
hscale=2;
- ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_gscon[label="BSC conn FSM"];
+ 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 bsc_gscon [label="IF BSC releases, from BSSMAP Clear Request"];
- bsc note bsc [label="lchan_release() may be called with sacch_deact=true or false.
- Currently, the only time lchan_release(sacch_deact=true) is invoked is upon BSSMAP Clear
- Command, i.e. when the MSC instructs to stop using an active lchan.
- Some error handling code paths however directly invoke
- rsl_rf_chan_release(error=1, SACCH_DEACTIVATE)."];
-
- ---;
- bsc_gscon note bsc_gscon [label="Rx: BSSMAP Clear Request from MSC"];
- bsc <- bsc_gscon [label="gsm0808_clear()"];
- bsc box bsc [label="lchan_release(sacch_deact=1)"];
- bsc box bsc [label="lchan->state = LCHAN_S_REL_REQ"];
- bsc box bsc [label="_lchan_handle_release(sacch_deact=1)"];
- 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"];
- ms <= bsc [label="RR Channel Release"];
- ms note bsc [label="There is no ACK for RR Channel Release"];
- bsc box bsc [label="rsl_deact_sacch()"];
- bts <= bsc [label="RSL Deactivate SACCH"];
- bsc abox bsc [label="Start T3109 (net->T3109, t3109_expired())"];
+ 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"];
...;
- --- [label="If T3109 expires"];
- bsc box bsc [label="t3109_expired()"];
- bsc box bsc [label="rsl_rf_chan_release(error=1)"];
- bts <= bsc [label="RSL Release Request (Local End)..."];
- bts <= bsc [label="...for each SAPI, except link_id=0"];
- bsc box bsc [label="lchan->state = LCHAN_S_REL_REQ"];
- bts <= bsc [label="RSL RF Channel Release"];
- ---;
+ 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 rbox bsc [label="continue in the 'Common' part"];
- --- [label="END: 'BSSMAP Clear Request'"];
+ 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 bsc_gscon [label="IF BSC releases, from implicitly unused lchan"];
- bsc note bsc [label="The BSC may release old unused lchans after Handover, or release lchans
- after some error condition."];
- bsc note bsc [label="BSC decides to release an unused lchan"];
- bsc box bsc [label="lchan_release(sacch_deact=0)"];
- bsc box bsc [label="lchan->state = LCHAN_S_REL_REQ"];
- bsc box bsc [label="_lchan_handle_release(sacch_deact=0)"];
- bts <= bsc [label="RSL Release Request (Local End)..."];
- bts <= bsc [label="...for all SAPIs"];
...;
- bts note bsc_gscon [linecolor="red",
- label="There seems to be no timer watching over RSL Release Request!"];
+
+ 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 [label="RSL Release Confirm..."];
- bts => bsc [label="...for all SAPIs"];
- bsc rbox bsc [label="continue in the 'Common' part"];
- ---;
+ 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"];
...;
-
- ms rbox bsc_gscon [label="IF MS releases"];
- ms => bts [label="DISC"];
- bts => bsc [label="RLL Release Ind..."];
- bts => bsc [label="...for each SAPI"];
- bsc rbox bsc [label="continue in the 'Common' part"];
- ---;
+ 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 bsc_gscon [label="Common"];
- --- [label="for each SAPI (?)"];
- bts => bsc [label="RLL Release Confirm / RLL Release Ind"];
- bsc box bsc [label="abis_rsl_rx_rll()"];
- bsc box bsc [label="mark lchan->sapis[link_id] = LCHAN_SAPI_UNUSED"];
- bsc box bsc [label="rll_indication()"];
- bsc box bsc [label="for each bsc_rll_req matching this link_id:
- disable timer, call cb(BSC_RLLR_IND_REL_IND)"];
- bsc box bsc [label="rsl_handle_release()"];
- --- [label="IF all SAPIs are unused"];
- bsc box bsc [label="Stop T3109"];
- bsc note bsc [label="T3109 was started if the MSC requested the release"];
- bsc abox bsc [label="Start T3111 (net->T3111 value, t3111_expired())"];
- --- [label="END: all SAPIs are unused"];
- bsc -> bsc_gscon [label="GSCON_EV_RLL_REL_IND (only if RLL Release Ind)"];
- --- [label="END: for each SAPI"];
-
...;
- bsc box bsc [label="T3111 expires"];
- bsc box bsc [label="rsl_rf_chan_release()"];
- bsc box bsc [label="Stop T3109"];
- bsc note bsc [label="[If lchan->state is LCHAN_S_REL_ERR, don't do anything]"];
- bsc abox bsc [label="Start lchan->act_timer (4s, lchan_deact_tmr_cb())"];
- bts <= bsc [label="RSL RF Channel Release"];
+ 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"];
...;
- --- [label="IF lchan->act_timer expires"];
- bsc box bsc [label="lchan_deact_tmr_cb()"];
- bsc box bsc [label="rsl_lchan_mark_broken(): lchan->state = LCHAN_S_BROKEN"];
- bsc box bsc [label="lchan_free() (see below)"];
- --- [label="END: 'lchan->act_timer expires'"];
+ 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 [label="RSL RF Channel Release ACK"];
- bsc box bsc [label="rsl_rx_rf_chan_rel_ack()"];
- bsc box bsc [label="Stop lchan->act_timer"];
- bsc box bsc [label="Stop T3111"];
-
- --- [label="IF lchan->state == LCHAN_S_BROKEN"];
- bsc note bsc [label="If an ACK comes in late, for specific BTS models, we may choose to 'repair'
- the lchan so that it is usable again, by calling do_lchan_free() directly (see below)."];
- bsc box bsc [label="rsl_rx_rf_chan_rel_ack() exits here and none of below actions happen.
- The lchan remains LCHAN_S_BROKEN indefinitely."];
- --- [label="END: lchan->state == LCHAN_S_BROKEN"];
- bsc box bsc [label="do_lchan_free()"];
- --- [label="IF lchan->state == LCHAN_S_REL_ERR"];
- bsc note bsc [label="If release failed, we take the lchan back into operation after due
- timeout"];
- bsc abox bsc [label="Start lchan->error_timer (T3111+2, error_timeout_cb())"];
- bsc note bsc [label="do_lchan_free() continues, async:"];
+ bts => bsc_lchan [label="RSL RF Channel Release ACK"];
...;
- bsc box bsc [label="error_timeout_cb()"];
- bsc box bsc [label="lchan->state = LCHAN_S_NONE"];
- bsc box bsc [label="dyn TS: activate PDCH..."];
- --- [label="ELSE"];
- bsc box bsc [label="lchan->state = LCHAN_S_NONE"];
- --- [label="END: lchan->state == LCHAN_S_REL_ERR"];
- bsc box bsc [label="lchan_free()"];
- --- [label="IF conn is still associated (and not dyn TS in switchover)"];
- bsc -> bsc [label="S_LCHAN_UNEXPECTED_RELEASE"];
- bsc box bsc [label="handle_release()"];
- bsc box bsc [label="Stop T10"];
- bsc note bsc [linecolor=orange,label="conn->T10 is actually dead code, it is never started.
- Instead, the conn FSM starts ST_WAIT_ASS_COMPL with a T10 value."];
- bsc -> bsc_gscon [label="GSCON_EV_RR_ASS_FAIL"];
- bsc -> bsc_gscon [label="GSCON_EV_TX_SCCP: BSSMAP Clear Request"];
- bsc box bsc [label="bsc_clear_handover()"];
- bsc box bsc [label="Stop T3103"];
- bsc box bsc [label="free handover struct"];
- bsc box bsc [label="lchan->conn = NULL"];
- --- [label="END: 'conn is still associated'"];
- bsc box bsc [label="Stop T3101"];
- bsc note bsc [label="T3101 is started when sending an RR Immediate Assignment"];
- bsc -> bsc [label="S_CHALLOC_FREED"];
- bsc -> bsc [label="rll_lchan_signal()"];
- bsc box bsc [label="for each bsc_rll_req matching this lchan:
- disable timer, call cb(BSC_RLLR_IND_REL_IND)"];
+ bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
+ bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
}
diff --git a/doc/lchan.msc b/doc/lchan.msc
new file mode 100644
index 000000000..9b7d663c4
--- /dev/null
+++ b/doc/lchan.msc
@@ -0,0 +1,306 @@
+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"];
+
+ bts box mgw_msc [label="lchan allocation sequence"];
+ bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
+
+ 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"];
+ |||;
+ |||;
+
+ 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."];
+ ...;
+ --- [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="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"];
+
+ ...;
+ ...;
+ ...;
+
+ 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()"];
+ ...;
+ --- [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?'"];
+ |||;
+
+ 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"];
+ ...;
+ --- [label="on timeout"];
+ bsc_lchan rbox bsc_lchan [label="Continue at: 'On any error', 'unrecoverable'"];
+ ---;
+ ...;
+ bts => bsc_lchan [label="RSL RF Channel Release Ack"];
+
+ bsc_lchan box bsc_lchan [label="lchan_fsm_post_rf_release()"];
+ |||;
+ --- [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?)"];
+ ...;
+ bsc_lchan box bsc_lchan [label="timer expires"];
+ --- [label="END: 'an error cause was indicated on LCHAN_EV_RELEASE'"];
+ |||;
+ 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"];
+ |||;
+ |||;
+
+ bts rbox mgw_msc [label="On any error"];
+ |||;
+ --- [label="IF FOR_MS_CHANNEL_REQUEST && !sent_chan_activ"];
+ bts <= bsc_lchan [label="RR Immediate Assign Reject"];
+ |||;
+ --- [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 unrecoverable error"];
+ bsc_lchan abox bsc_lchan [label="LCHAN_ST_BORKEN"];
+ bsc_lchan note bsc_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
+ '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()"];
+}
diff --git a/doc/ms-channel-request.msc b/doc/ms-channel-request.msc
index c0ef60fc7..1c5b4bfb3 100644
--- a/doc/ms-channel-request.msc
+++ b/doc/ms-channel-request.msc
@@ -1,8 +1,8 @@
msc {
- hscale=3;
- ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_gscon[label="BSC conn FSM"];
+ hscale=2;
+ ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_lchan[label="BSC lchan FSM"];
- ms note bsc_gscon [label="lchan allocation sequence for RSL Channel Request"];
+ ms note bsc_lchan [label="lchan allocation sequence for RSL Channel Request"];
ms => bts [label="RR Channel Request"];
bts => bsc [label="RSL Channel Request"];
@@ -13,51 +13,47 @@ msc {
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_alloc(SDCCH, allow_bigger=0)"];
+ 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()"];
+ 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 abox bsc [label="Start lchan->act_timer (4s, lchan_act_tmr_cb())"];
-
- bsc box bsc [label="rsl_chan_activate_lchan(RSL_ACT_INTRA_IMM_ASS)"];
- --- [label="is the chosen lchan on dynamic timeslot that is currently used as PDCH?"];
- bsc box bsc [linecolor=red,label="Osmocom style dyn TS use the lchan->act_timer for an RSL RF
- Channel Release, to release PDCH mode. This will actually overwrite above act_timer!"];
- 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="gsm0808_assign_req() returns early"];
- bsc_gscon abox bsc_gscon [label="ST_WAIT_ASS_COMPL (GSM0808_T10_VALUE=6s)"];
+ 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)"];
...;
- 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!"];
- ...;
- 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"];
+ --- [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)"];
---;
-
- bsc box bsc [label="lchan->state = LCHAN_S_ACT_REQ"];
- bts <= bsc [label="RSL Chan Activ: Immediate Assignment"];
...;
- bsc note bsc [label="Timeout of lchan->act_timer causes the
- lchan->state to go to LCHAN_S_BROKEN, but no events or actions
- are triggered."];
+ 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 [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 (has no effect)"];
- bsc note bsc [label="Since this was an Immediate Assignment, no further action is required on
- behalf of the BSC. The MS is now free to use the lchan."];
+ 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
new file mode 100644
index 000000000..79e56c95f
--- /dev/null
+++ b/doc/timeslot-fsm.dot
@@ -0,0 +1,36 @@
+digraph G {
+rankdir=TB;
+
+ invisible [style="invisible"]
+ invisible2 [style="invisible"]
+ NOT_INITIALIZED
+ lchan [label="lchan FSM",shape=box3d];
+ UNUSED
+ IN_USE
+ BORKEN
+ PDCH
+ WAIT_PDCH_ACT
+ WAIT_PDCH_DEACT
+
+ invisible -> NOT_INITIALIZED [label="OML\nOpstart ACK",style=dotted]
+ invisible2 -> NOT_INITIALIZED [label="RSL\nbootstrapped",style=dotted]
+
+ NOT_INITIALIZED -> UNUSED [label="OML+RSL ready"]
+
+ UNUSED -> IN_USE [label="first\nlchan\nrequested\nby lchan\nFSM"]
+ IN_USE -> UNUSED [label="last lchan\nunused"]
+
+ UNUSED -> PDCH [label="onenter:\ndedicated PDCH\nand GPRS\nis enabled"]
+ UNUSED -> WAIT_PDCH_ACT [label="onenter:\ndyn TS\nand GPRS\nis enabled"]
+ WAIT_PDCH_ACT -> PDCH [label="dyn TS:\nPDCH activated"]
+
+ PDCH -> WAIT_PDCH_DEACT [label="dyn TS:\nlchan of specific\npchan requested"]
+ WAIT_PDCH_DEACT -> UNUSED [label="lchan\nunused\n(e.g. error)",style=dashed]
+ WAIT_PDCH_DEACT -> IN_USE [label="dyn TS:\nPDCH released"]
+
+ lchan -> {UNUSED} [label="TS_EV_LCHAN_\nREQUESTED",style=dotted]
+ {IN_USE} -> lchan [label="LCHAN_EV_\nTS_READY",style=dotted]
+ lchan -> IN_USE [label="TS_EV_LCHAN_\nUNUSED",style=dotted]
+
+ {WAIT_PDCH_ACT,WAIT_PDCH_DEACT} -> BORKEN [label=timeout,style=dashed]
+}
diff --git a/doc/timeslot.msc b/doc/timeslot.msc
new file mode 100644
index 000000000..9a8c36075
--- /dev/null
+++ b/doc/timeslot.msc
@@ -0,0 +1,98 @@
+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 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)"];
+
+ |||;
+ 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)"];
+
+ |||;
+ --- [label="IF: dynamic timeslot"];
+ bsc_ts abox bsc_ts [label="WAIT_PDCH_ACT (?s, Tnnnn)"];
+ bts <= bsc_ts [label="RSL Chan Activ of PDCH",ID="Osmocom style"];
+ bts <= bsc_ts [label="RSL PDCH Act",ID="ip.access style"];
+ ...;
+ --- [label="timeout:"];
+ bsc_ts abox bsc_ts [label="BORKEN"];
+ ---;
+ ...;
+ 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)"];
+
+ --- [label="END: GPRS enabled?"];
+ ...;
+ ...;
+
+ bts rbox bsc_lchan [label="UNUSED, on event"];
+ bsc_ts abox bsc_ts [label="UNUSED"];
+ bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED (data=lchan)"];
+ bsc_ts abox bsc_ts [label="IN_USE"];
+ 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, second lchan"];
+ 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 <- 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"];
+ ---;
+ ...;
+ ...;
+
+
+ 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 <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED"];
+ bsc_ts abox bsc_ts [label="WAIT_PDCH_DEACT (?s, Tnnnn)"];
+ bts <= bsc_ts [label="RSL RF Chan Release of PDCH",ID="Osmocom style"];
+ bts <= bsc_ts [label="RSL PDCH Deact",ID="ip.access style"];
+ ...;
+ --- [label="timeout:"];
+ bsc_ts abox bsc_ts [label="BORKEN"];
+ bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_ERROR"];
+ ---;
+ ...;
+ bts => bsc_ts [label="RSL RF Chan Release ACK",ID="Osmocom style"];
+ bts => bsc_ts [label="RSL PDCH Deact ACK",ID="ip.access style"];
+ --- [label="IF all lchan->fi->state == LCHAN_ST_UNUSED"];
+ bsc_ts note bsc_lchan [label="If the lchan FSM decided to give up in the
+ meantime, nr of active lchans might have dropped back to zero."];
+ bsc_ts abox bsc_ts [label="UNUSED"];
+ bsc_ts note bsc_ts [label="onenter at UNUSED state will trigger back to
+ PDCH mode"];
+ |||;
+ --- [label="IF at least one lchan->state != LCHAN_ST_UNUSED"];
+ bsc_ts abox bsc_ts [label="IN_USE"];
+ bsc_ts rbox bsc_ts [label="Continue at 'IN_USE' above"];
+ ...;
+ ...;
+
+ bts rbox bsc_lchan [label="on erratic event"];
+ bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_ERROR"];
+ bsc_lchan box bsc_lchan [label="release lchan"];
+ ...;
+ bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
+ bsc_ts note bsc_ts [label="log error but ignore"];
+ ...;
+
+}
diff --git a/doc/ts-and-lchan-fsm-lifecycle.msc b/doc/ts-and-lchan-fsm-lifecycle.msc
new file mode 100644
index 000000000..79d32c530
--- /dev/null
+++ b/doc/ts-and-lchan-fsm-lifecycle.msc
@@ -0,0 +1,116 @@
+msc {
+ hscale=2;
+ bts [label="MS/BTS"], bsc[label="BSC"], bsc_ts[label="BSC timeslot FSM"], bsc_lchan[label="BSC lchan FSM"];
+
+ bsc box bsc [label="gsm_bts_alloc()"];
+ bsc box bsc [label="bts->c0 = gsm_bts_trx_alloc()"];
+ bsc -> bsc_ts;
+ bsc_ts box bsc_ts [label="trx->ts[*].fi = osmo_fsm_inst_alloc(timeslot_fsm)"];
+ bsc_ts abox bsc_ts [label="TS_ST_NOT_INITIALIZED"];
+ bsc -> bsc_lchan;
+ bsc_lchan box bsc_lchan [label="ts->lchan[*].ts = ts;\nts->lchan[*].nr = i;"];
+ bsc_lchan box bsc_lchan [label="ts->lchan[*].fi = NULL"];
+ bsc_ts note bsc_lchan [label="lchan_select() will only pick lchans from initialized timeslots of
+ the right pchan kind. lchan_select() shall OSMO_ASSERT(lchan->fi)."];
+ ...;
+ ...;
+
+ bts rbox bsc_lchan [label="reading config file"];
+ ...;
+ bsc box bsc [label="timeslot N"];
+ bsc box bsc [label="phys_chan_config X"];
+ bsc_ts box bsc_ts [label="ts->pchan_from_config = X"];
+ bsc_ts note bsc_ts [label="still TS_ST_NOT_INITIALIZED"];
+ ...;
+ bsc box bsc [label="trx 1..*"];
+ bsc box bsc [label="bts->trx_list add gsm_bts_trx_alloc()"];
+ bsc_ts rbox bsc_lchan [label="same as for c0 above"];
+ ...;
+ ...;
+ bts rbox bsc_lchan [label="Starting Operation"];
+ bts => bsc_ts [label="OML Channel OPSTART ACK"];
+ bsc_ts box bsc_ts [label="ts_on_oml_opstart()"];
+ bsc_ts box bsc_ts [label="ts->pchan_on_init = pchan_from_config"];
+ --- [label="IF dedicated TS"];
+ bsc_ts box bsc_ts [label="ts->pchan = ts->pchan_on_init"];
+ --- [label="ELSE: dyn TS"];
+ bsc_ts box bsc_ts [label="ts->pchan = NONE"];
+ --- [label="END: dyn TS"];
+ bsc_ts note bsc_lchan [label="Normally, the lchan FSM never terminates. Logic dictates that
+ the lchan is a child of the timeslot FSM, but it's not actually of functional importance
+ beyond basic sanity. Parent term event: TS_EV_LCHAN_UNUSED"];
+ bsc_ts box bsc_ts [label="Determine N = maximum number of lchans applicable to pchan_on_init"];
+ bsc_ts -> bsc_lchan;
+ bsc_lchan box bsc_lchan [label="ts->lchan[all N].type = osmo_fsm_inst_alloc(lchan_fsm)"];
+ bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED\n(initial state)"];
+ bsc_ts -> bsc_ts [label="ts_check_init()"];
+ ...;
+ bsc -> bsc_ts [label="RSL bootstrapped"];
+ bsc_ts -> bsc_ts [label="ts_check_init()"];
+ ...;
+ bsc_ts box bsc_ts [label="ts_check_init()"];
+ --- [label="as soon as both OML and RSL are ready:"];
+ bsc_ts box bsc_ts [label="ts_on_init()"];
+ bsc_ts abox bsc_ts [label="TS_ST_UNUSED"];
+ --- [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"];
+ ...;
+ bsc_ts abox bsc_ts [label="PDCH"];
+ --- [label="END: dyn TS"];
+ --- [label="END: OML and RSL ready"];
+ ...;
+ bsc box bsc [label="lchan_select() picks an unused lchan"];
+ bsc -> bsc_lchan [label="lchan_allocate()"];
+ 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 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 -> bsc_lchan [label="LCHAN_EV_RELEASE"];
+ bsc_lchan note bsc_lchan [label="...RSL RF Chan Release..."];
+ 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"];
+ --- [label="dyn TS"];
+ bsc_ts note bsc_ts [label="possibly switch to PDCH"];
+ ---;
+ ...;
+ ...;
+ bts rbox bsc_lchan [label="BTS RSL is dropped"];
+ bsc box bsc [label="ipaccess_drop_rsl()"];
+ 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."];
+ 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)"];
+ ...;
+ --- [label="when RSL comes back later:"];
+ bsc -> bsc_ts [label="RSL bootstrapped"];
+ bsc_ts box bsc_ts [label="ts_check_init()"];
+ bsc_ts rbox bsc_ts [label="see ts_check_init() above"];
+ ...;
+ ...;
+ bts rbox bsc_lchan [label="BTS OML is dropped"];
+ bsc note bsc [label="As part of OML drop, RSL is also dropped:"];
+ bsc box bsc [label="ipaccess_drop_rsl()"];
+ bsc -> bsc_ts [label="ts[*]:"];
+ bsc_ts abox bsc_ts [label="TS_ST_NOT_INITIALIZED"];
+ bsc rbox bsc [label="see 'BTS RSL is dropped' above"];
+ bsc -> bsc_ts [label="ts[*]:"];
+ bsc_ts -> bsc_lchan [label="lchan[*]:"];
+ bsc_lchan box bsc_lchan [label="osmo_fsm_inst_term()"];
+ bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED (ignored)"];
+ bsc_lchan box bsc_lchan [label="lchan->fi = NULL"];
+ bsc rbox bsc [label="Continue at 'Starting Operation'"];
+
+}