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