diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/Makefile.am | 15 | ||||
-rw-r--r-- | doc/assignment.msc | 248 | ||||
-rw-r--r-- | doc/handover-inter-bsc-mo.msc | 37 | ||||
-rw-r--r-- | doc/handover-inter-bsc-mt.msc | 154 | ||||
-rw-r--r-- | doc/handover.msc | 241 | ||||
-rw-r--r-- | doc/lchan-fsm.dot | 53 | ||||
-rw-r--r-- | doc/lchan-release.msc | 190 | ||||
-rw-r--r-- | doc/lchan.msc | 306 | ||||
-rw-r--r-- | doc/ms-channel-request.msc | 68 | ||||
-rw-r--r-- | doc/timeslot-fsm.dot | 36 | ||||
-rw-r--r-- | doc/timeslot.msc | 98 | ||||
-rw-r--r-- | doc/ts-and-lchan-fsm-lifecycle.msc | 116 |
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'"]; + +} |